结构体的匿名字段:
结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为名匿名字段。
匿名字段默认采用类型名作为字段名,结构体要求类型必须唯一
结构体中匿名字段的简单使用
package main
import ("fmt")
// 结构体匿名
type Person struct {
string
int
}
func main() {
var p1 = Person{
"张三",
18,
}
fmt.Println("%v",p1)
}
结构体的类型
结构体的字段类型可以是:基本数据类型、也可以是切片、Map 以及结构体
如果结构体的字段类型是:指针,slice,和map的零值都是 ni1,即还没有分配空间
如果需要使用这样的字段,需要先make,才能使用
package main
import ("fmt")
// 结构体匿名
type Person struct {
name string
age int
hobby []string
map1 map[string]string
}
func main() {
var p1 Person
p1.name = "张三"
p1.age = 18
// 可以这样定义
// p1.hobby = []string{"吃饭","睡觉","打豆豆"}
p1.hobby = make([]string,2,6)
p1.hobby[0] = "吃饭"
p1.hobby[1] = "睡觉"
p1.map1 = make(map[string]string)
p1.map1["address"] = "王者峡谷"
p1.map1["phone"] = "123456789"
fmt.Println("%v",p1)
}
结构体嵌套结构体
package main
import ("fmt")
type User struct{
Username string
Password string
// 表示:User结构体嵌套Address结构体
Address Address
}
type Address struct{
City string
Phone string
}
func main() {
var u User
u.Username = "张三"
u.Password = "123456"
u.Address.City = "北京"
u.Address.Phone = "123456789"
fmt.Printf("%#v", u)
}
main.User{Username:"张三", Password:"123456", Address:main.Address{City:"北京", Phone:"123456789"}}
嵌套匿名结构体
type User struct{
Username string
Password string
// 表示:User结构体嵌套Address结构体
Address
// 等价与:Address Address ===> Address 嵌套匿名结构体
}
type Address struct{
City string
Phone string
}
修改结构体的另外一种方式
先看 User 自己有没有直接字段 Phone;
如果没有,再看它嵌入的匿名字段 Address 有没有 Phone;
如果有,就解析成 u.Address.Phone。
总结:当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。
package main
import ("fmt")
type User struct{
Username string
Password string
// 表示:User结构体嵌套Address结构体
Address
}
type Address struct{
City string
Phone string
}
func main() {
var u User
u.Username = "张三"
u.Password = "123456"
u.Address.City = "北京"
// 为啥这样也能够正常修改呢 ?
u.Phone = "123456789"
fmt.Printf("%#v", u)
}
main.User{Username:"张三", Password:"123456", Address:main.Address{City:"北京", Phone:"123456789"}}
结构体中有相同的字段,优先外层
package main
import ("fmt")
type User struct{
Username string
Password string
// 表示:User结构体嵌套Address结构体
Phone string // 结构体中有相同的字段
Address
}
type Address struct{
City string
Phone string // 结构体中有相同的字段
}
func main() {
var u User
u.Username = "张三"
u.Password = "#XC"
u.Phone = "123456789"
fmt.Printf("%#v", u)
}
规则:外层优先
Go 在查找 u.Phone 时,会按这个顺序:
先找 User 有没有接字段 Phone;
如果有,就用 User.Phone;
如果没有,才去嵌入字段 Address 里找 Address.Phone。
所以这里因为 User 自己就有 Phone,就直接修改了 User.Phone,不会去碰 Address.Phone。
结构体中有相同的字段,设置值时必须指明设置哪一个结构体
Address和 Info结构体中都有City字段,
如果我们设置 city字段时,必须写明设置哪一个结构体,否则会报错的哈。
u.City = "cd" 会报错。
因为City字段是Address和Info结构体中都有的。我们需要指明设置哪一个结构体。
package main
import ("fmt")
type User struct{
Username string
Password string
Phone string
// 下面是结构体的嵌套
Address
Info
}
type Address struct{
City string
Phone string
}
type Info struct{
City string
}
func main() {
var u User
u.Username = "张三"
// 会报错的哈。会报错的哈
u.City = "cd"
fmt.Printf("%#v", u)
}
通过结构体的嵌套来实现继承
package main
import ("fmt")
type Animal struct {
name string
}
func (a Animal) run() {
fmt.Println("跑")
}
type Dog struct {
age string
// 这个是匿名结构体,通过结构体的嵌套来实现继承哈
Animal
}
func (d Dog) wang() {
fmt.Println("汪汪汪")
}
func main() {
var d = Dog{
age: "1岁",
Animal: Animal{name:"小狗"},
}
d.wang()
// 我们可以去调用动物的跑,我们通过嵌套结构体来实现继承
d.run()
}
输出:
汪汪汪
跑
一个结构体中可以嵌套另一个结构体或结构体指针
package main
import ("fmt")
type Animal struct {
name string
}
func (a Animal) run() {
fmt.Println("跑")
}
type Dog struct {
age string
// 嵌套的是一个指针;某个内存地址所对应的值
*Animal
}
func (d Dog) wang() {
fmt.Println("汪汪汪")
}
func main() {
var d = Dog{
age: "1岁",
// 通过[&变量名]来获取变量的内存地址
Animal: &Animal{name:"小狗"},
}
d.wang()
// 我们可以去调用动物的跑,我们通过嵌套结构体来实现继承
d.run()
}
&变量名: 表示变量的内存地址,也叫做指针
*p表示:某个内存地址所对应的值;