## 定义 Go语言可以通过自定义的方式形成新的类型,结构体就是这些类型中的一种复合类型,结构体是由零个或多个任意类型的值聚合成的实体,每个值都可以称为结构体的成员。 结构体成员也可以称为“字段”,这些字段有以下特性: - 字段拥有自己的类型和值; - 字段名必须唯一; - 字段的类型也可以是结构体,甚至是字段所在结构体的类型。 使用关键字 type 可以将各种基本类型定义为自定义类型,基本类型包括整型、字符串、布尔等。结构体是一种复合的基本类型,通过 type 定义为自定义类型后,使结构体更便于使用。 ``` type 类型名 struct{ 字段 类型 } ``` 例如: ``` type Person struct{ name string age int } ``` 同类型的变量也可以写在一行 ``` type Person struct{ name, email string age int } ``` ## 实例化 结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存,因此必须在定义结构体并实例化后才能使用结构体的字段。 实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。 Go语言可以通过多种方式实例化结构体,根据实际需要可以选用不同的写法。 **var 实例化方式** ``` package main import "fmt" type Person struct{ name string age int } func main() { var tom = Person tom.name = "Tom" tom.age = 18 // var tom = Person{"Tom", 18} 可以省略字段名,但是顺序必须一一对应 fmt.Println(tom) // {Tom 18} } ``` **new 实例化方式** ``` package main import "fmt" type Person struct{ name string age int } func main() { tom := new(Person) tom.name = "Tom" tom.age = 18 fmt.Println(tom) // &{Tom 18} } ``` ## 结构体初始化 **使用“键值对”初始化结构体** ``` type Person struct{ name string age int } user := Person{name: "Tony", age: 18} ``` **省略键初始化结构体** ``` type Person struct{ name string age int } user := Person{"Tony", 18} ``` **初始化匿名结构体** 匿名结构体的初始化写法由结构体定义和键值对初始化两部分组成,结构体定义时没有结构体类型名,只有字段和类型定义,键值对初始化部分由可选的多个键值对组成: ``` init := struct { // 匿名结构体字段定义 字段 字段类型 … }{ // 字段值初始化,注意每行结尾必须有逗号 初始化字段: 字段的值, … } ``` ``` package main import "fmt" func main() { init := struct{ name string age int }{ name: "Tom", age: 18, } fmt.Printf("%v", init) // {Tom 18} } ``` ## 匿名字段 Go语言支持只提供类型,而不写字段名的方式,也就是匿名字段,或称为嵌入字段。 当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。 ``` package main import "fmt" type Person struct{ name string age int } type Tom struct{ Person height int } func main() { tom := Tom{Person{"Tom", 18}, 180} fmt.Printf("%v", tom.name) // Tom // 通过Person作为字段名访问 fmt.Printf("%v", tom.Person.name) // Tom } ``` 自定义类型和内置类型等都可以作为匿名字段,而且还可以在相应的字段是进行函数操作: ``` package main import "fmt" type Person struct{ name string age int } // 类型定义 type Skills []string type Tom struct{ Person // 匿名字段,struct Skills // 匿名字段,自定义类型 string slice height int int // 内置类型作为匿名字段 } func main() { tom := Tom{Person:Person{"Tom", 18}, Skills: []string{"computer", "excel"}, height: 180} fmt.Printf("his name is:%s\n", tom.name) // he name is:Tom // 修改 skill 字段 tom.Skills = append(tom.Skills, "Python") fmt.Printf("his skills are:%v\n", tom.Skills) // he skills are:[computer excel Python] // 修改匿名内置类型 tom.int = 50 fmt.Printf("%d", tom.int) // 50 } ``` 如果 Person 里有个 phone 字段,而 Tom 里也有个 phone 字段,当通过 tom.phone 访问,会优先访问最外层的字段 这样就允许我们去重载通过匿名字段继承的一些字段,当然如果我们想访问重载后对应匿名类型里面的字段,可以通过匿名字段名来访问。 ``` package main import "fmt" type Person struct{ name , phone string age int } type Tom struct{ Person // 匿名字段,struct phone string } func main() { tom := Tom{Person:Person{"Tom", "xxx", 18}, phone: "xxxxxx"} fmt.Printf("his phone is:%s\n", tom.phone) // his phone is:xxxxxx fmt.Printf("his phone is:%s\n", tom.Person.phone) // his phone is:xxx } ```