匿名组合
一、 匿名字段
一般情况下,定义结构体的时候是字段名与其类型一一对应,实际上Go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。
当匿名字段也是一个结构体的时候,那么这个结构体所拥有的全部字段都被隐式地引入了当前定义的这个结构体。
//人
type Person struct {
name string
sex byte
age int
}
//学生
type Student struct {
Person //匿名字段,那么默认Student就包含了Person的所有字段
id int
addr string
}
Person
也就是上面定义的这个Person
结构体。
二、 初始化
//人
type Person struct {
name string
sex byte
age int
}
//学生
type Student struct {
Person//匿名字段,那么默认Student就包含了Person的所有字段
id int
addr string
}
func main() {
//顺序初始化
s1 := Student{Person{"mike",'m',18},1,"sz"}
//s1 = {Person:{name:mike sex:109 age:18}id:1 addr:sz}
fmt.Printf("s1=%+v\n",s1)
//s2 := Student{"mike",'m',18,1,"sz"}//err
//部分成员初始化1
s3 := Student{Person:Person{"lily",'f',19},id:2}
//s3 = {Person:{name:lily sex:102 age:19}id:2 addr:}
fmt.Printf("s3=%+v\n",s3)
//部分成员初始化2
s4 := Student{Person:Person{name:"tom"},id:3}
//s4 = {Person:{name:tomsex:0age:0}id:3addr:}
fmt.Printf("s4=%+v\n",s4)
}
然后我们在main
里面调用Student
就能直接对Person
里面的属性赋值。
三、 成员的操作
var s1 Student//变量声明
//给成员赋值
s1.name = "mike"//等价于s1.Person.name="mike"
s1.sex = 'm'
s1.age = 18
s1.id = 1
s1.addr = "sz"
fmt.Println(s1) //{{mike 109 18}1 sz}
var s2 Student//变量声明
s2.Person = Person{"lily",'f',19}
s2.id = 2
s2.addr = "bj"
fmt.Println(s2) //{{lily 102 19}2 bj}
或者我们声明一个Student
的变量也能调用它里面的属性。
四、 同名字段
//人
type Person struct{
name string
sex byte
age int
}
//学生
type Student struct{
Person //匿名字段,那么默认Student就包含了Person的所有字段
id int
addr string
name string //和Person中的name同名
}
func main(){
var s Student//变量声明
//给Student的name,还是给Person赋值?
s.name = "mike"
//{Person:{name:sex:0age:0}id:0addr:name:mike}
fmt.Printf("%+v\n",s)
//默认只会给最外层的成员赋值
//给匿名同名成员赋值,需要显示调用
s.Person.name = "yoyo"
//Person:{name:yoyosex:0age:0}id:0addr:name:mike}
fmt.Printf("%+v\n",s)
}
如果命名重名的话我们调用只会给最外层的使用,也就是Student
,如果说你要给Person
赋值的话得明确表示。s.Person.name="张三"
。
五、 其它匿名字段
1. 非结构体类型
所有的内置类型和自定义类型都是可以作为匿名字段的:
type mystr string//自定义类型
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person //匿名字段,结构体类型
int //匿名字段,内置类型
mystr //匿名字段,自定义类型
}
func main() {
//初始化
s1 := Student{Person{"mike",'m',18},1,"bj"}
//{Person:{name:mikesex:109age:18}int:1mystr:bj}
fmt.Printf("%+v\n",s1)
//成员的操作,打印结果:mike,m,18,1,bj
fmt.Printf("%s,%c,%d,%d,%s\n",s1.name,s1.sex,s1.age,s1.int,s1.mystr)
}
不一样要结构体才能作为匿名字段,其实定义一个类型也是一样的。
2. 结构体指针类型
type Person struct { //人
name string
sex byte
age int
}
type Student struct {//学生
*Person //匿名字段,结构体指针类型
id int
addr string
}
func main() {
//初始化
s1 := Student{&Person{"mike",'m',18},1,"bj"}
//{Person:0xc0420023e0id:1addr:bj}
fmt.Printf("%+v\n",s1)
//mike,m,18
fmt.Printf("%s,%c,%d\n",s1.name,s1.sex,s1.age)
//声明变量
var s2 Student
s2.Person = new(Person)//分配空间
s2.name = "yoyo"
s2.sex = 'f'
s2.age = 20
s2.id = 2
s2.addr = "sz"
//yoyo10220220
fmt.Println(s2.name,s2.sex,s2.age,s2.id,s2.age)
}
在匿名方法里面也是能使用指针的,只要在前面加上&
就行。