一、基本说明
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
二、结构体声明
type 结构体名称 struct{ field type field type }
例子:
type Dog struct { Name string Age int Color string }
注:在创建一个结构体变量后,如果没有给字段赋值,都应该对应一个零值(默认值),布尔类型为false,数值类型为0,字符串为"",指针、slice和map的零值时nil,即没有分配空间。
三、结构体变量和访问结构体字段
- 方式一:直接声明
var dog Dog
- 方式二:{}
package main import ( "fmt" ) type Dog struct { Name string Age int Color string } func main() { dog := Dog{"来福", 3, "白色"} fmt.Printf("dog=%v\n", dog) }
输出结果:
dog={来福 3 白色}
- 方式三:new()
package main import ( "fmt" ) type Dog struct { Name string Age int Color string } func main() { dog := new(Dog) // dog是一个指针,因此标准的给字段赋值应该是(*dog).Name = "来福" (*dog).Age = 3 (*dog).Color = "白色" // go设计者为了程序员使用方便,底层会对dog.Name = "来福"进行处理,会给dog加上取值运算(*dog).Name = "来福" dog.Name = "来福" // 等价于(*dog).Name = "来福" dog.Age = 3 // 等价于(*dog).Age = 3 dog.Color = "白色" // 等价于(*dog).Color = "白色" fmt.Printf("dog=%v\n", *dog) }
输出结果:
dog={来福 3 白色}
- 方式四:
package main import ( "fmt" ) type Dog struct { Name string Age int Color string } func main() { dog := &Dog{"来福", 3, "白色"} fmt.Printf("dog=%v\n", *dog) }
输出结果:
dog={来福 3 白色}
说明:
- 第三种方式和第四种方式返回的是结构体指针
- 结构体指针访问字段的标准方式应该是:(*结构体指针).字段名,比如(*dog).Name = "来福"
- 但是go做了一个简化,也支持结构体指针.字段名,比如:dog.Name = "来福",更加符合程序员使用习惯,go编译器底层对dog.Name做了转化(*dog).Name
四、结构体和结构体变量的区别
- 结构体是自定义的数据类型,代表一类事物
- 结构体变量(实例)是具体的,实际的,代表一个具体变量
五、结构体在内存中的示意图
六、注意细节
- 结构体所有字段在内存中是连续分布的
package main import ( "fmt" ) type Point struct { x, y int } type Rect struct { LeftUp, RightDown Point } func main() { rect := Rect{Point{10, 20}, Point{30, 40}} fmt.Printf("rect.LeftUp.x地址=%v\n,rect.LeftUp.y地址=%v\n,rect.RightDown.x地址=%v\n,rect.RightDown.y地址=%v\n", &rect.LeftUp.x, &rect.LeftUp.y, &rect.RightDown.x, &rect.RightDown.y) }
输出结果:
rect.LeftUp.x地址=0xc0000124e0 ,rect.LeftUp.y地址=0xc0000124e8 ,rect.RightDown.x地址=0xc0000124f0 ,rect.RightDown.y地址=0xc0000124f8
- 结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数和类型)
package main import ( "fmt" ) type A struct { Num int Num2 int } type B struct { Num int Num2 int } func main() { var a A var b B a = A(b) // 可以转换,但是有要求,就是结构体字段要完全一样(包括:名字,类型,个数,顺序) fmt.Println("a=", a, "b=", b) }
输出结果:
a= {0 0} b= {0 0}
- 结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
package main import ( "fmt" ) type integer int func main() { var i integer var j int j = int(i) fmt.Println("i=", i, "j=", j) }
输出结果:
i= 0 j= 0
- struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
package main import ( "encoding/json" "fmt" ) type Dog struct { Name string `json:"name"` // `json:"name"`就是struct tag Age int `json:"age"` Color string `json:"color"` } func main() { dog := Dog{"来福", 3, "白色"} // 将dog变量序列化为json字符串 // json.Marshal函数中使用反射 jsonStr, err := json.Marshal(dog) if err != nil { fmt.Println("json转换错误") } fmt.Println("dog=", string(jsonStr)) }
输出结果:
dog= {"name":"来福","age":3,"color":"白色"}