1. 什么是结构体?
结构体是自定义的类型,是若干字段的集合。
2. 结构体的定义
具名结构体:
type Person struct {
First_name string
Last_name string
age int // 开头为小写,不能被其它的包使用
Sex bool
}
匿名结构体:
person_1 := struct {
name string
age int
sex bool
}{"Robinho", 25, true,}
fmt.Println(person_1) //输出:{Robinho 25 true}
这种写法并没有定义一种新的结构体类型,而是仅仅创建了一个新的结构体变量。
在实际开发过程中很少有需要用这种写法。
3. 结构体变量声明(写字段,不写字段)
写字段名,顺序可以与结构体字段声明的顺序不同:
person_3 := Person{
Last_name : "Iverson",
First_name : "Allen",
sex : true,
Age : 25,
}
fmt.Println(person_3) //输出:{Allen Iverson 25 true}
不写字段名,顺序必须保持一致:
person_4 := Person{"Allen","Iverson",25,true}
fmt.Println(person_4) //输出:{Allen Iverson 25 true}
4. 匿名字段
在定义结构体时,我们也可以仅仅指定字段类型而不指定字段名字,这种字段叫做匿名字段。
注意:一个类型只能出现一次,重复会报错。
匿名字段虽然没有指定名字,但它有一个默认的名字,就是类型名:
type Club struct {
string // 名字
int // 冠军数量
}
var rng Club
rng.int = 8
rng.string = "RNG" // 匿名字段,默认字段名就是类型名
fmt.Println(rng) //输出:{RNG 8}
不过这种实际用处也不是很大,即使只有一两个字段,还是给个字段名更直观一点,没必要偷这种懒。
5. 结构体嵌套
结构体是可以嵌套的:
type Player struct{
Name string
Age int
club Club
}
info := Player{
Name : "Uzi",
Age : 23,
club : Club {"RNG", 8},
}
uzi.club.int = 9 // 如果要使用被嵌套的结构体中的字段,必须这样写
fmt.Println(info) // 输出结果为:{Uzi 23 {RNG 9}}
6. 字段提阶
结构体嵌套,如果想使用被嵌套的结构体中的字段,必须通过被嵌套结构体的字段名,这样不是很方便。
所以我们可以将被嵌套的结构体声明为匿名字段,来实现字段提阶,被嵌套结构体中的字段就成了提阶字段,这样就可以直接用这些字段了,仿佛这些字段本身就是属于外部结构体一样。
type Address struct{
City string
Province string
}
type Brand struct {
Name string
Industry string
Address
}
laoganma := Brand{}
laoganma.Name = "LaoGanMa"
laoganma.Industry = "Food"
laoganma.City = "GuiYang"
laoganma.Province = "GuiZhou" // 提阶字段,可以直接使用
fmt.Println(laoganma) // 输出结果为:{LaoGanMa Food {GuiYang GuiZhou}}
7. 结构体的初始值
如果结构体变量没有被初始化,那么它各个字段的初始值就是各自类型的零值。
player := Player{}
fmt.Println(player) // 输出结果为:{ 0 { 0}}
8. 结构体的比较
-- 结构体是值类型的,如果其字段是可以比较的,那么该结构体就是可以比较的,直接用 == 操作符来比较即可。
-- 如果结构体包含不可比较的字段,那么这个结构体类型是不可以比较的。
-- 如果两个结构体变量中的非空字段都相等,则认为这两个结构体变量相等。
player1 := Player{"", 23, Club{"RNG", 8}}
player2 := Player{"", 23, Club{"RNG", 8}}
if player1 == player2 {
fmt.Println("player1 == player2") // 此句代码被执行
}
9. 导出结构体和字段
回顾一下,在导入包的部分提到过,函数和包级别的变量想要被导出,命名必须以大写开头。
结构体同样如此!
结构体中的字段同样如此!!
10. String()函数
对于一个自定义类型,如果实现了String()方法,那么fmt默认会调用String()。
实际上就相当于自己定义了一个自定义类型怎么被fmt打印输出。
例子可以看上一篇 指针 中的Human结构体。