当创建了两个结构体,其中一个结构体通过匿名嵌套在另一个结构体中,如下面的定义

1
2
3
4
5
6
7
8
9
type Person struct {
	Name string
	Age  int
}

type Student struct {
	Person
	Grade string
}

Person 为匿名结构体嵌套在了Student 内,那么此时如果想要初始化一个Student对象时该如何初始化呢?

依次给出每个字段的值

这种最好理解,但是却不能在初始化的时候直接给出

1
2
3
4
5
6
s1 := Student{
    Grade: "一年级",
    // 以下两行不能编译
    Name: "yyx",
    Age: 18
}
unknown field Name in struct literal
1
2
3
4
5
6
s1 := Student{
		Grade: "一年级",
}
s1.Name = "yyx"
s1.Age = 18
fmt.Println(s1)
{{yyx 18} 一年级}
1
2
3
4
5
6
7
s1 := Student{
    Grade: "一年级",
}
s1.Name = "yyx"
s1.Age = 18
fmt.Println(s1.Name) // yyx
fmt.Println(s1.Person.Name) //yyx
s1.Names1.Person.Nameyyx

具名赋值

这种赋值就是在初始化的时候写上对应的结构体名称

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func main() {
	s1 := Student{
		Grade: "一年级",
		Person: Person{
			Name: "yyx",
			Age:  18,
		},
	}
	fmt.Println(s1.Name)
	fmt.Println(s1.Person.Name)
}

先初始化匿名结构体变量

这种方式其实和上面的方式是一样的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func main() {
	// 先初始化一个Person 对象
	p := Person{
		Name: "yangyanxing",
		Age:  18,
	}
	s := Student{
		Grade:  "一年级",
		Person: p,  // 再将p赋值给匿名结构体
	}
	fmt.Printf("%#v\n", s)
	fmt.Println(s.Name)
	fmt.Println(s.Age)
	fmt.Println(s.Grade)
}

这里有个问题,嵌入的结构体不在同个包怎么办?

1
2
3
4
├── go.mod
├── main.go
└── utils
    └── utils.go

上面main.go中的Student 结果体嵌入了utils包下的Person结构体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// utils.go
package utils

type Person struct {
	Name string
	Age  int
}


//main.go
type Student struct {
	utils.Person
	Grade string
}

这时候采用第一种方法先初始化变量再对属性进行赋值还是可以的

1
2
3
4
5
6
7
8
func main() {
	s1 := Student{
		Grade: "一年级",
	}
	s1.Name = "yyx1111"
	fmt.Println(s1.Name)
	fmt.Println(s1.Person.Name)
}
invalid field name utils.Person in struct literal

这里只需要把utils 去掉,直接使用Person来赋值就可以了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func main() {
	p := utils.Person{
		Name: "yangyanxing",
		Age:  18,
	}
	s := Student{
		Grade:  "一年级",
		Person: p,
	}

	fmt.Printf("%#v\n", s)
	fmt.Println(s.Name)
	fmt.Println(s.Age)
	fmt.Println(s.Grade)
}

但是又会引出一个新的问题,如果一个结构体引入了两个不同包下的同名的结构体又该怎么处理呢?

1
2
3
4
5
6
├── common
│   └── common.go
└── utils
    └── utils.go
├── go.mod
├── main.go

这里我又新建了一个common目录,里面有一个common.go,里面也有一个Person 结构体,和utils.go 中的结构体不一样, 多了一个性别

1
2
3
4
5
6
7
package common

type Person struct {
	Name string
	Age  int
	Sex  string
}

此时如果在main.go 中定义的Student如下

1
2
3
4
5
type Student struct {
	utils.Person
	common.Person 
	Grade string
}
Person redeclared

其次,如果你实在是想两个都引入,那么只能将其中一个变为具名属性

1
2
3
4
5
type Student struct {
	utils.Person
	Cp common.Person 
	Grade string
}

这样,就可区分是utils下的Person还是common下的Person了

结构体本身和匿名结构体如果有相同的属性名怎么办?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type Person struct {
	Name string
	Age  int
}

type Student struct {
	Person
	Name  string
	Grade string
}

func main() {
	p := Person{
		Name: "yangyanxing",
		Age:  18,
	}
	s := Student{
		Grade:  "一年级",
		Person: p,
	}

	fmt.Println(s.Name) // 这里为空 ""
	fmt.Println(s.Person.Name) // yangyanxing
	fmt.Println(s.Age) //18
	fmt.Println(s.Grade)
}
对象.属性