zoukankan      html  css  js  c++  java
  • Go 面向对象之结构体

    #### Go 面向对象之结构体
    最近有四天没更新公众号,有一些事情耽误了,生活就是这样,总会一些事情让人措不及防;
    ***山浓水浅,坐看流年***

    1. Go 也支持面向对象编程(OOP) 但是它和传统的面向对象编程还是有一些区别,并不是纯粹的面向对象编程;
    2. Go 中没有类(class), Go 中struct 和其它编程语言中的类有同等地位,所以我们可以理解Go 是基于struct 来实现OOP;
    3. Go 面向对象很简洁,没有传统OOP 的继承,方法重载,构造函数等等;
    4. Go 面向对象仍有继承,封装,多态的特性,只是它的实现与传统的OOP语言不同;
    ##### 结构体与结构体变量(实例/对象)的关系图

     
    ---
    说明:
    1. 将一类事物的特性提取出来(比如猫类),形成一个新的数据类型就是一个结构体;
    2. 通过这个结构体,可以创建多个变量(实例/对象);
    3. 事物可以是猫类,也可以是其它的类...;
    案例:
    package main
    
    import "fmt"
    
    // 定义一个结构体,类似于类
    // 将Cat 的各个字段/属性,放入到结构体中
    type Cat struct {
       Name string
       Age uint
       Color string
       Hobby string
    }
    func main(){
       // 声明一个Cat 变量,也就是实例
       var a1 Cat
       a1.Name = "小花"
       a1.Age = 2
       a1.Color = "black"
       a1.Hobby = "老鼠"
       fmt.Println(a1)
       fmt.Printf("name=%s
    ",a1.Name)
       fmt.Printf("age=%d
    ",a1.Age)
       fmt.Printf("color=%s
    ",a1.Color)
       fmt.Printf("hobby=%s
    ",a1.Hobby)
    }
    

      


    ---
    结构体与结构体变量(实例)的区别
    1. 结构体是自定义的数据类型,代表一类事物;
    2. 结构体变量是具体的,实际的,代表一个具体的变量;
    ---
    ##### 结构体变量在内存中的布局

      

    ##### 如何声明结构体
    基本语法:
    type 结构体名称 struct {
    field1 type
    field2 type
    ...
    }
    例如:
    typt Person struct {
    Name string
    Age int
    Class string
    }
    ##### 字段属性
    字段是结构体的组成部分,一般是基本数据类型,数组,同时也可以是引用类型;
    注意事项:
    1. 字段声明语法同变量一样: 字段名 字段类型
    2. 在创建一个结构体变量后,如果没有给字段赋值,每个字段都对应一个默认值,引用类型默认值为nil;
    3. 不同结构体变量的字段是独立的,互不影响: 结构体是值类型;
    package main
    
    import "fmt"
    
    // 如果结构体里的字段是引用类型的: slice map channel;
    // 在使用前需要make分配内存才能使用;
    type Person struct {
       Name string
       Age int
       Hobby [3]string
       ptr *string
       slice []int
       Parents map[string]string
    }
    type Cat struct {
       Name string
       Age int
    }
    func main(){
       var a1 Person
       fmt.Println(a1) //{0 [] nil [] map[]}
       if a1.ptr == nil {
          fmt.Println("ptr is nil")
       }
       if a1.slice == nil {
          fmt.Println("slice is nil")
       }
       if a1.Parents == nil {
          fmt.Println("parents is nil")
       }
       // 结构体字段是引用类型的话,使用前需要make
       a1.slice = make([]int,10)
       a1.slice[0] = 1
       a1.slice[1] = 2
       a1.slice[2] = 3
       a1.Parents = make(map[string]string)
       a1.Parents["name"] = "aaaa"
       a1.Parents["friendly"] = "father"
       fmt.Println(a1) // { 0 [  ] <nil> [1 2 3 0 0 0 0 0 0 0] map[friendly:father name:aaaa]}
       // 不同结构体变量间互不影响
       var c1 Cat
       var c2 Cat
       c1.Name = "c1"
       c2.Name = "c2"
       c1.Age = 1
       c2.Age = 2
       fmt.Println(c1,c2) //{c1 1} {c2 2} 
    }
    

      


    ---
    ##### 创建结构变量和访问结构体字段
    package main
    
    import "fmt"
    
    type Cat struct {
       Name string
       Age int
    }
    func main(){
       // 方式1: 先声明,再赋值
       var c1 Cat
       c1.Name = "c1"
       c1.Age = 1
       fmt.Println(c1) //{c1 1}
       // 方式2: 字面量方式
       var c2 Cat = Cat{"c2",2}
       fmt.Println(c2) //{c2 2}
       // 方式3: 类型推导方式
       c3 := Cat{"c3",3}
       fmt.Println(c3) //{c3 3}
       // 方式4: new 方式
       var c4 *Cat = new(Cat)
       c4.Name = "c4"
       c4.Age = 4
       fmt.Println(*c4)
       // 方式5: &{} 方式
       var c5 *Cat = &Cat{}
       c5.Name = "c5"
       c5.Age = 5
       fmt.Println(*c5)
       // 方式4,方式5 返回的都是结构体的指针类型
    }
    

      


    1. 第4,5 种方式返回的是***结构体指针***;
    2. 结构体指针访问字段的标准方式应该是:(*结构体指针).字段名, 如:(*c4).Name = "c4";
    3. Go 做了简化,支持***结构体指针.字段名***,如:c4.Name = "c4",Go 编译器底层自动处理了;
    ---
    ##### 结构体使用注意事项
    1. 结构体中所有的字段在内存中是连续的;
    2. 结构体是用户自定义的类型,在和其它类型转换时需要有完全相同的字段(名称,个数,类型);
    3. 结构体进行type 定义,Go 认为是新的数据类型,可以和基本数据类型进行强转;
    4. 结构体每个字段上可以写tag,tag 可以通过反射机制获取,常用的场景是序列化和反序列化;
    package main
    
    import (
       "encoding/json"
       "fmt"
    )
    
    type Person struct {
       Name string
       Age int
       Hobby string
    }
    type Student struct {
       Name string
       Age int
       Hobby string
    }
    type Cat struct {
       Name string `json:"name"`
       Age int `json:"age"`
    }
    func main(){
       var p1 Person
       p1.Name = "p1"
       p1.Age = 22
       p1.Hobby = "run"
       // 结构体变量的地址
       fmt.Printf("p1 address: %p
    ",&p1)
       fmt.Printf("p1.Name address: %p
    ",&p1.Name) // 0xc0000562d0
       fmt.Printf("p1.Age address: %p
    ",&p1.Age) //   0xc0000562e0 , 一个string 是16 字节
       fmt.Printf("p1.Hobby address: %p
    ",&p1.Hobby)//0xc0000562e8 , 一个int 在64 位系统中为8字节
       // 类型之间强转
       var s1 Student
       s1 = Student(p1)
       fmt.Println(s1)
       fmt.Printf("s1 type is %T
    ",s1) // Student
       // struct tag
       var c1 Cat
       c1.Name = "小花"
       c1.Age = 12
       jsonStr,err := json.Marshal(c1)
       if err != nil {
          fmt.Println(err)
       }
       // 输出的是结构体中tag 定义的名称
       fmt.Println(string(jsonStr)) // {"name":"小花","age":12} 
    }
    

      个人微信公众号上有最新内容,欢迎关注交流学习

  • 相关阅读:
    Educational Codeforces Round 104 (Rated for Div. 2) A B C D E
    Codeforces Round #701 (Div. 2) A B C D
    Codeforces Round #700 (Div. 2) A B C D1
    记录一次Boot整合Batch框架无法连接达梦数据库的问题
    关于Java中的volatile关键字的总结,适合了解不太多的人
    写个日志切面追踪,可以更直接查看项目执行的各种信息打印。
    sqlServer实现group by 之后 聚合操作之拼接结果
    SQL CURSOR 游标
    SQL case when
    Redis版本
  • 原文地址:https://www.cnblogs.com/Mail-maomao/p/11458935.html
Copyright © 2011-2022 走看看