go语言中结构体匿名字段和嵌套结构体(继承)

结构体的匿名字段:

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为名匿名字段。

匿名字段默认采用类型名作为字段名,结构体要求类型必须唯一

结构体中匿名字段的简单使用

复制代码
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表示:某个内存地址所对应的值;