结构体嵌套 #
一、嵌套概述 #
Go通过结构体嵌套实现组合,支持匿名字段和字段提升。
二、命名嵌入 #
2.1 基本用法 #
go
type Address struct {
City string
Country string
}
type Person struct {
Name string
Address Address
}
p := Person{
Name: "Alice",
Address: Address{
City: "Beijing",
Country: "China",
},
}
fmt.Println(p.Address.City) // Beijing
2.2 访问方式 #
go
p.Address.City = "Shanghai"
fmt.Println(p.Address.City)
三、匿名嵌入 #
3.1 基本用法 #
go
type Person struct {
Name string
Address // 匿名嵌入
}
p := Person{
Name: "Alice",
Address: Address{
City: "Beijing",
},
}
fmt.Println(p.City) // Beijing(字段提升)
fmt.Println(p.Address.City) // Beijing
3.2 字段提升 #
匿名字段的字段被提升到外层:
go
type Inner struct {
X int
}
type Outer struct {
Inner
Y int
}
o := Outer{Inner: Inner{X: 10}, Y: 20}
fmt.Println(o.X) // 10(提升)
fmt.Println(o.Inner.X) // 10
fmt.Println(o.Y) // 20
3.3 内置类型嵌入 #
go
type MySlice []int
func (s MySlice) Sum() int {
sum := 0
for _, v := range s {
sum += v
}
return sum
}
type Data struct {
MySlice
}
d := Data{MySlice: MySlice{1, 2, 3}}
fmt.Println(d.Sum()) // 3
fmt.Println(d.MySlice.Sum()) // 3
四、方法继承 #
4.1 继承方法 #
go
type Animal struct {
Name string
}
func (a Animal) Speak() {
fmt.Println("Some sound")
}
type Dog struct {
Animal
}
func main() {
d := Dog{Animal{Name: "Buddy"}}
d.Speak() // Some sound
}
4.2 方法重写 #
go
func (d Dog) Speak() {
fmt.Println("Woof!")
}
func main() {
d := Dog{Animal{Name: "Buddy"}}
d.Speak() // Woof!
d.Animal.Speak() // Some sound
}
4.3 方法链 #
go
type Base struct{}
func (b Base) Method1() {
fmt.Println("Base.Method1")
}
type Middle struct {
Base
}
func (m Middle) Method2() {
fmt.Println("Middle.Method2")
}
type Derived struct {
Middle
}
func main() {
d := Derived{}
d.Method1() // Base.Method1
d.Method2() // Middle.Method2
}
五、字段冲突 #
5.1 同名字段 #
go
type A struct {
X int
}
type B struct {
X int
}
type C struct {
A
B
}
c := C{A: A{X: 1}, B: B{X: 2}}
// fmt.Println(c.X) // 错误:歧义
fmt.Println(c.A.X) // 1
fmt.Println(c.B.X) // 2
5.2 外层覆盖内层 #
go
type Inner struct {
X int
}
type Outer struct {
Inner
X int // 覆盖Inner.X
}
o := Outer{Inner: Inner{X: 1}, X: 2}
fmt.Println(o.X) // 2(外层)
fmt.Println(o.Inner.X) // 1
六、指针嵌入 #
6.1 指针嵌入 #
go
type Person struct {
Name string
Address *Address
}
p := Person{
Name: "Alice",
Address: &Address{
City: "Beijing",
},
}
fmt.Println(p.City) // Beijing
6.2 nil检查 #
go
type Person struct {
Address *Address
}
func (p Person) GetCity() string {
if p.Address == nil {
return "Unknown"
}
return p.Address.City
}
七、组合模式 #
7.1 组合优于继承 #
Go推荐使用组合而非继承:
go
type Writer interface {
Write([]byte) (int, error)
}
type Reader interface {
Read([]byte) (int, error)
}
type ReadWriter struct {
Reader
Writer
}
7.2 实际应用 #
go
type Logger struct {
prefix string
}
func (l Logger) Log(msg string) {
fmt.Printf("[%s] %s\n", l.prefix, msg)
}
type Service struct {
Logger
name string
}
func main() {
s := Service{
Logger: Logger{prefix: "INFO"},
name: "MyService",
}
s.Log("Service started")
}
八、嵌入接口 #
8.1 基本用法 #
go
type Reader interface {
Read() string
}
type Writer interface {
Write(string)
}
type ReadWriter interface {
Reader
Writer
}
8.2 结构体嵌入接口 #
go
type Handler struct {
http.Handler
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("Before")
h.Handler.ServeHTTP(w, r)
fmt.Println("After")
}
九、实际应用 #
9.1 装饰器模式 #
go
type DataSource interface {
Read() string
}
type FileSource struct {
content string
}
func (f *FileSource) Read() string {
return f.content
}
type CachedSource struct {
DataSource
cache string
}
func (c *CachedSource) Read() string {
if c.cache == "" {
c.cache = c.DataSource.Read()
}
return c.cache
}
9.2 中间件模式 #
go
type Handler struct {
next http.Handler
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("Middleware before")
h.next.ServeHTTP(w, r)
fmt.Println("Middleware after")
}
9.3 混入模式 #
go
type Timestamp struct {
CreatedAt time.Time
UpdatedAt time.Time
}
func (t *Timestamp) Touch() {
t.UpdatedAt = time.Now()
}
type User struct {
ID int
Name string
Timestamp
}
type Article struct {
ID int
Title string
Timestamp
}
十、最佳实践 #
10.1 优先组合 #
go
// 好:组合
type Service struct {
Logger
DB
}
// 避免:深层嵌套
type A struct { B }
type B struct { C }
type C struct { D }
10.2 避免过度嵌套 #
go
// 简单清晰
type User struct {
Name string
Address Address
}
// 过度嵌套
type User struct {
Profile struct {
Basic struct {
Name string
}
}
}
10.3 明确字段来源 #
go
type Person struct {
Name string
Address
}
p := Person{}
p.City = "Beijing" // 清晰
p.Address.City = "Beijing" // 更明确
十一、总结 #
嵌套要点:
| 特性 | 说明 |
|---|---|
| 命名嵌入 | 显式访问 |
| 匿名嵌入 | 字段提升 |
| 方法继承 | 继承嵌入类型的方法 |
| 字段冲突 | 需要显式指定 |
关键点:
- 组合优于继承:Go推荐组合
- 字段提升:匿名字段提升到外层
- 方法继承:继承嵌入类型的方法
- 冲突处理:同名字段需要显式指定
- 指针嵌入:注意nil检查
准备好学习结构体标签了吗?让我们进入下一章!
最后更新:2026-03-26