1.1 什么是结构体
结构体也就是类似java中的类,是一种由一系列具有相同类型或不同类型的数据构成的数据集合
1.2 结构体定义
type struct_variable_type struct {member definition;member definition;...member definition;}// 一旦定义了结构体类型,它就能用于变量的声明variable_name := structure_variable_type {value1, value2...valuen}
示例:
type User struct {name stringage intsex byte}func main() {// 按照顺序进行初始化p1 := User{"ada", 19, 'F'}fmt.Println(p1)// 按照field:value进行初始化,这样可以任意顺序p2 := User{age: 24,sex: 'M',name: "zled",}fmt.Println(p2)//new方式,未设置初始值的,会赋予类型的默认初始值p3 := new(User)p3.name = "zzled"p3.sex = 'M'fmt.Println(p3)// 普通定义,分别设置var p4 Userp4.sex = 'F'p4.age = 18p4.name = "ada"fmt.Println(p4)}/*{ada 19 70}{zled 24 77}&{zzled 0 77}{ada 18 70}*/
1.3 结构体的访问
直接通过对象名.field进行访问即可
p1 := User{"ada", 19, 'F'}fmt.Println(p1.name)/*ada*/
1.4 结构体指针
用法与普通指针相同,可以查看上一节的函数指针使用。
type User struct {name stringage intsex byte}func main() {u := User{"ada", 19, 'F'}fmt.Println(u)structPointer(&u)}/*结构体指针*/func structPointer(u *User) {fmt.Println("指针所指变量的地址是: ", u)fmt.Println("指针所指变量的值是: ", *u)fmt.Printf("%T\n", u)fmt.Printf("%s\n", u.name)fmt.Printf("%d\n", u.age)fmt.Printf("%c\n", u.sex)}/*{ada 19 70}指针所指变量的地址是: &{ada 19 70}指针所指变量的值是: {ada 19 70}*main.Userada19F*/
1.5 匿名字段(继承字段)
可以用字段来创建结构,这些字段只包含一个没有字段名的类型。这些字段被称为匿名字段。
type Human struct {name stringage intweight int}type Student struct {Human // 匿名字段,那么默认Student就包含了Human的所有字段speciality string}func main() {s := Student{Human: Human{"ada", 19, 45},speciality: "resident Evil",}fmt.Println(s)fmt.Println(s.name)fmt.Println(s.age)fmt.Println(s.weight)fmt.Println(s.speciality)}/*{{ada 19 45} resident Evil}ada1945resident Evil*/
可以使用”.”的方式进行调用匿名字段中的属性值 实际就是字段的继承
1.6 结构体嵌套
一个结构体可能包含一个字段,而这个字段反过来就是一个结构体。这些结构被称为嵌套结构。
示例:
type Address struct {city, state string}type Person struct {name stringage intaddress Address}func main() {var p Personp.name = "ada"p.age = 21p.address = Address{city: "Chicago",state: "Illinois",}fmt.Println("Name:", p.name)fmt.Println("Age:", p.age)fmt.Println("City:", p.address.city)fmt.Println("State:", p.address.state)}/*Name: adaAge: 21City: ChicagoState: Illinois*/
1.7 提升字段
在结构体中属于匿名结构体的字段被称为提升字段,因为它们可以被访问,就好像他们属于拥有匿名结构字段的结构一样。理解这个定义是相当复杂的。
type Address struct {city, state string}type Person struct {name stringage intAddress // 注意与1.6例子的区别}func main() {var p Personp.name = "ada"p.age = 21p.Address = Address{ // 注意与1.6例子的区别city: "Chicago",state: "Illinois",}fmt.Println("Name:", p.name)fmt.Println("Age:", p.age)fmt.Println("City:", p.city) // 注意与1.6例子的区别fmt.Println("State:", p.state) // 注意与1.6例子的区别}/*Name: adaAge: 21City: ChicagoState: Illinois*/
1.9 结构体比较
结构体是值类型,如果每个字段都具有可比性,则是可比较的,如果他们对应的字段相等,则认为两个结构体变量是相等的。
示例:
type Person struct {name stringage int}func main() {var p1 Personp1.name = "ada"p1.age = 21var p2 Personp2.name = "ada"p2.age = 21var p3 Personp3.name = "lion"p3.age = 20fmt.Println(p1 == p2)fmt.Println(p2 == p3)fmt.Println(p1 == p3)}/*truefalsefalse*/
1.8 结构体作为函数参数
1.9 make()和new()的区别
看起来没有区别,都是在堆上分配内存,但它们的行为不同,适用于不同的类型。
- new(T) 为每个新的类型T分配一片内存,初始化为0并且返回类型为*T的内存地址:这种方法返回一个指向类型为T,值为0的地址的地址,它适用于值类型如:数组和结构体;它相当于&T{}。
- make(T) 返回一个类型为T的初始值,它只适用于3种内建的引用类型:slice、map和channel。
换言之,new函数分配内存,make函数初始化。
第一幅图中:
var p *[]int = new([]int) // *p == nil; with len and cap 0p := new([]int)
第二幅图中:
p :=make([]int,0)
切片已经被初始化,但是指向一个空的数组。
以上两种方式实用性都不高。下面的方法比较实用:
var a []int = make([]int,10,50)b := make([]int,10,50)
这样分配一个有50个int值的数组,并且创建一个长度为10,容量为50的切片v,该切片指向数组的前10个元素。
// 如果只有一个参数,那么长度和容量相同v := make([]int, 10)fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))// 如果数字有两个,则第一个是长度,第二个是容量,且必须长度小于等于容量b := make([]int, 10, 50)fmt.Printf("长度为%d,容量为%d\n", len(b), cap(b))/*长度为10,容量为10长度为10,容量为50*/
初始完成后,会动态进行调整。
v := make([]int, 3, 5)fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))b := [4]int{1, 2, 3, 4}v = b[:]fmt.Println(v)fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))d := [6]int{1, 2, 3, 4, 5, 6}v = d[:]fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))/*长度为3,容量为5[1 2 3 4]长度为4,容量为4长度为6,容量为6*/
获取长度和容量
v := make([]int, 3, 5)fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))d := [5]int{1, 2, 3, 4, 5}v = d[1:4]fmt.Println(v)fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))/*长度为3,容量为5[2 3 4]长度为3,容量为4*/
