天天看点

Go 面向对象之结构体

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

1. Go 也支持面向对象编程(OOP) 但是它和传统的面向对象编程还是有一些区别,并不是纯粹的面向对象编程;  
2. Go 中没有类(class), Go 中struct 和其它编程语言中的类有同等地位,所以我们可以理解Go 是基于struct 来实现OOP;   
3. Go 面向对象很简洁,没有传统OOP 的继承,方法重载,构造函数等等;  
4. Go 面向对象仍有继承,封装,多态的特性,只是它的实现与传统的OOP语言不同; 
##### 结构体与结构体变量(实例/对象)的关系图      
Go 面向对象之结构体
---
说明:  
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\n",a1.Name)
   fmt.Printf("age=%d\n",a1.Age)
   fmt.Printf("color=%s\n",a1.Color)
   fmt.Printf("hobby=%s\n",a1.Hobby)
}
      

  

---
结构体与结构体变量(实例)的区别
1. 结构体是自定义的数据类型,代表一类事物;  
2. 结构体变量是具体的,实际的,代表一个具体的变量;  
---
##### 结构体变量在内存中的布局        
Go 面向对象之结构体
##### 如何声明结构体
基本语法:  
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\n",&p1)
   fmt.Printf("p1.Name address: %p\n",&p1.Name) // 0xc0000562d0
   fmt.Printf("p1.Age address: %p\n",&p1.Age) //   0xc0000562e0 , 一个string 是16 字节
   fmt.Printf("p1.Hobby address: %p\n",&p1.Hobby)//0xc0000562e8 , 一个int 在64 位系统中为8字节
   // 类型之间强转
   var s1 Student
   s1 = Student(p1)
   fmt.Println(s1)
   fmt.Printf("s1 type is %T\n",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} 
}
      

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

Go 面向对象之结构体

每天进步一点点!加油