1.命名嵌入
结构体命名嵌入是指结构体中的属性对应的类型也是结构体
package main
import "fmt"
type Addrs struct {
Region string
Street string
}
type Users struct {
ID int
Name string
Addr Addrs
}
func main() {
//结构体命名嵌入
var user Users = Users{
ID: 2,
Name: "aa",
Addr: Addrs{
Region: "bbb",
Street: "ccc",
},
}
fmt.Println(user)
fmt.Println(user.Addr.Region)
user.Addr.Region = "543"
fmt.Println(user.Addr.Region)
}
2.匿名嵌入
结构体匿名嵌入是指将已定义的结构体名直接声明在新的结构体中,从而实现对以后已有类
型的扩展和修改
在访问和修改嵌入结构体的属性值时,可以通过对象名.结构体名称.属性名的方式进行访问
和修改,结构体名称可以省略(匿名成员有一个隐式的名称),因此不能嵌套两个相同名称
的结构体。当被嵌入结构体和嵌入结构体有相同的属性名时,在访问和修改嵌入结构体成员
的属性值时不能省略结构体名称
package main
import "fmt"
//匿名嵌入结构体就是两种情况
//1.嵌入结构体与外层有相同属性,省略匿名访问,访问的是外层属性
//2.两个嵌入结构体都有同属性,访问不能省略匿名,必须全路径访问
type Addrs struct {
Region string
Street string
}
type Users struct {
ID int
Name string
Addr Addrs
}
type Company struct {
Name string
}
//如果匿名嵌入结构体 嵌入2个或者多个结构体并且都具有相同的属性,那么访问必须全路径访问不然会报错找不到
//因为查找对应属性省略匿名的话他是递进去查找如果最外层有那么就直接返回,没有会继续到下一层去找
type Employee struct {
Users
Salary float64
Company
}
func main() {
m1 := Employee{}
m1.Users.Name = "aa"
m1.Company.Name = "bb"
fmt.Printf("%#v", m1)
}
3.指针类型嵌入
结构体嵌入(命名&匿名)类型也可以为结构体指针
(1)命名
package main
import "fmt"
//指针命名嵌入
type Addrs struct {
Region string
Street string
}
type Users struct {
ID int
Name string
Addr *Addrs
}
func main() {
//未初始化值 返回对应属性的零值 指针的零值是nil
m := Users{}
fmt.Printf("%#v\n", m)
m = Users{
ID: 1,
Name: "aa",
Addr: &Addrs{
Region: "西安",
Street: "锦未央",
},
}
fmt.Printf("%#v\n", m)
fmt.Println(m.Addr.Region)
m.Addr.Region = "北京"
fmt.Println(m.Addr.Region)
}
(2)匿名
package main
import "fmt"
//指针匿名嵌入
type Addrs struct {
Region string
Street string
Name string
}
type Users struct {
ID int
Name string
*Addrs
}
func main() {
//未初始化值 返回对应属性的零值 指针的零值是nil
m := Users{}
fmt.Printf("%#v\n", m)
m = Users{
ID: 1,
Name: "aa",
Addrs: &Addrs{
Region: "西安",
Street: "锦未央",
Name: "bb",
},
}
fmt.Printf("%#v\n", m)
fmt.Println(m.Addrs.Region)
fmt.Println(m.Name)
}
4.值类型与指针类型嵌入的区别
(1)值类型
值类型赋值给变量1 变量1赋值给变量2 修改变量2 变量1并不会被修改
package main
import "fmt"
//结构体是值类型 在赋值的时候相当于copy了一份 修改赋值之后 并不会影响其本身,如果结构体中有指针引用另说
type Addrs struct {
Region string
Street string
}
type Users struct {
ID int
Name string
Addr Addrs
bb []int
}
//这里修改对之前并没有影响
func change(m Users) {
m.Name = "yyy"
}
//因为这里传递的是指针 是一个内存地址 那么修改之后内存地址对应的就会被改
func Change(m *Users) {
m.Name = "nnn"
}
func main() {
m1 := Users{}
m2 := m1
m2.Name = "aa"
m2.Addr.Street = "bbb"
m2.bb = []int{1, 2, 3, 4}
fmt.Printf("%#v\n", m1)
fmt.Printf("%#v\n", m2)
change(m2)
fmt.Printf("%#v\n", m2)
Change(&m2)
fmt.Printf("%#v\n", m2)
}
(2)指针类型
值类型赋值给变量1 变量1赋值给变量2 修改变量2 变量1会被修改
package main
import "fmt"
type Addrs struct {
Region string
Street string
}
type Users struct {
ID int
Name string
Addr *Addrs
}
func main() {
m1 := Users{
ID: 11,
Name: "aaa",
Addr: &Addrs{
Region: "北京",
Street: "宋家庄",
},
}
m2 := m1
m2.Name = "bb"
fmt.Printf("%#v\n", m1.Addr)
fmt.Printf("%#v\n", m2.Addr)
m2.Addr.Street = "bbb"
fmt.Printf("%#v\n", m1.Addr)
fmt.Printf("%#v\n", m2.Addr)
}
结构体中如果有切片映射这种引用类型 赋值多个变量也会被影响