Golang 中的匿名字段和提升字段

有时你会看到在 Golang 中定义结构体时,有种写法是只定义类型而不定义字段名。下面将介绍这种被称为匿名字段的语法,以及它能够实现的作用。

匿名字段

在定义结构体的时候,如果一个字段没有声明名称而只声明了类型,那么这个字段就是一个匿名字段(anonymous fields)。该字段的名称和类型一致。

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
package main

import (
"fmt"
)

type User struct {
name string
}

type Service struct {
User
string
int
}

func main() {
s := Service{
User: User{
name: "Jack",
},
string: "foo",
int: 1,
}
fmt.Printf("%s %s %d\n", s.User, s.string, s.int) // {Jack} foo 1
}

https://play.golang.org/p/oDE7NxiTWWf

提升字段

同时匿名字段还有一个附带效果,就是提升(promotion)。如果在结构体中定义一个子结构体作为匿名字段,那么这个子结构体的字段(promoted fields)和方法(promoted methods)都会被提升到父结构体中。

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
27
28
29
30
package main

import (
"fmt"
)

type user struct {
name string
}

func (u *user) Greet() {
fmt.Printf("Hello, I'm %s\n", u.name)
}

type Service struct {
name string
user
}

func main() {
s := Service{
name: "test service",
user: user{
name: "Jack",
},
}
fmt.Printf("%s %s\n", s.name, s.user.name) // Jack Jack
s.Greet() // Hello, I'm Jack
s.user.Greet() // Hello, I'm Jack
}

https://play.golang.org/p/zs_d4uknP8Z

需要注意,提升字段实际上是一个语法糖,被提升的方法中调用的属性还是子结构体的,并不能通过提升获取父结构体中的属性。