go语言中的结构体嵌入详解(最新推荐)

作者:

文章目录
  • 结构体嵌入 = 在一个结构体中,直接写另一个结构体类型,不写字段名 type Base struct { ID int Name string } type User struct { Base // 嵌入结构体(匿名字段) Age int } 等价于(语义上): type User struct { Base Base Age int } 但用法和能力完全不同(这是重点)。
  • Go 没有 extends,但结构体嵌入提供了: 能力 Go 结构体嵌入 代码复用 ✅ 方法复用 ✅ 多继承 ✅(可嵌入多个) 父子类型关系 ❌(不是 is-a)
  • type Logger struct{} func (l Logger) Log() { fmt.Println(“log”) } type Auth struct{} func (a Auth) Check() { fmt.Println(“auth”) } type Service struct { Logger Auth } s := Service{} s.Log() s.Check() 👉 Go 允许多个嵌入结构体
  • 这是 Go 非常核心的设计思想。
  • type MyInt int type Counter struct { MyInt } c := Counter{} c.MyInt = 10 ⚠️ 不如结构体嵌入常见,但合法
  • 对比项 嵌入结构体 普通字段 访问方式 u.ID u.Base.ID 方法提升 ✅ ❌ 接口继承 ✅ ❌ 语义 组合 拥有 📌 推荐原则:👉 想复用行为(方法) → 用嵌入👉 只是数据成员 → 用普通字段
  • ❌ 以为是继承(不是) ❌ 字段冲突没处理 ❌ 不理解指针嵌入 vs 值嵌入 ❌ 滥用嵌入(嵌太多层可读性差) 到此这篇关于go语言中的结构体嵌入详解的文章就介绍到这了,更多相关go语言结构体嵌入内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Go语言创建结构体实例对象的几种常用方式 go语言中空结构体的实现 go中结构体切片的实现示例 Go 数据库查询与结构体映射的示例详解 详解Go语言中空结构体的惯用法 GO语言中ni,零值与空结构体的使用 go语言中嵌套结构体的实现 简单聊聊Go语言中空结构体和空字符串的特殊之处
  • 目录
    • 一、什么是结构体嵌入?
    • 二、最直观的效果:字段“提升”(Promoted Fields)
      • 1️⃣ 直接访问被嵌入结构体的字段
    • 三、方法也会被“提升”(非常关键)
      • 1️⃣ 嵌入结构体的方法
    • 四、结构体嵌入 ≠ 继承,但很像
      • 五、嵌入多个结构体(类似多继承)
        • 六、字段 / 方法冲突规则(必考点)
          • 1️⃣ 同名字段冲突
          • 2️⃣ 子结构体“覆盖”嵌入结构体字段
        • 七、值嵌入 vs 指针嵌入(非常重要)
          • 1️⃣ 值嵌入
          • 2️⃣ 指针嵌入(推荐)
        • 八、嵌入结构体与接口的“神级配合”
          • 1️⃣ 嵌入结构体自动“继承”接口实现
        • 九、嵌入基础类型(不常用但要知道)
          • 十、结构体嵌入 vs 普通字段 对比
            • 十一、工程实践中的典型用法
              • 1️⃣ Web / 业务模型
              • 2️⃣ 装饰 / 组合模式
            • 十二、常见坑总结 ⚠️

              结构体嵌入 = 在一个结构体中,直接写另一个结构体类型,不写字段名

              type Base struct {
              	ID   int
              	Name string
              }
              type User struct {
              	Base   // 嵌入结构体(匿名字段)
              	Age int
              }

              等价于(语义上):

              type User struct {
              	Base Base
              	Age  int
              }
              

              但用法和能力完全不同(这是重点)。

              u := User{
              	Base: Base{
              		ID:   1,
              		Name: "Tom",
              	},
              	Age: 18,
              }
              fmt.Println(u.ID)        // 1
              fmt.Println(u.Name)      // Tom
              fmt.Println(u.Base.ID)   // 1(也可以)

              👉 Base 的字段被“提升”到了 User 上

              type Base struct{}
              func (b Base) Hello() {
              	fmt.Println("hello from Base")
              }
              type User struct {
              	Base
              }
              var u User 
              u.Hello() // 等价于 u.Base.Hello()

              📌 字段 + 方法都会被提升

              Go 没有 extends,但结构体嵌入提供了:

              能力 Go 结构体嵌入
              代码复用
              方法复用
              多继承 ✅(可嵌入多个)
              父子类型关系 ❌(不是 is-a)

              type Logger struct{}
              func (l Logger) Log() { fmt.Println("log") }
              type Auth struct{}
              func (a Auth) Check() { fmt.Println("auth") }
              type Service struct {
              	Logger
              	Auth
              }
              s := Service{}
              s.Log()
              s.Check()
              

              👉 Go 允许多个嵌入结构体

              type A struct {
              	Name string
              }
              type B struct {
              	Name string
              }
              type C struct {
              	A
              	B
              }

              ❌ 不能直接:

              c.Name // 编译错误:ambiguous selector
              

              ✅ 必须显式指定:

              c.A.Name 
              c.B.Name

              type Base struct {
              	Name string
              }
              type User struct {
              	Base
              	Name string
              }
              u := User{}
              u.Name = "UserName"      // 访问的是 User.Name
              u.Base.Name = "BaseName"
              

              📌 就近原则:优先访问最外层字段

              type User struct {
              	Base
              }
              
              • 拷贝一份 Base
              • 修改时改的是副本

              type User struct {
              	*Base
              }
              
              b := &Base{ID: 1}
              u := User{Base: b}
              u.ID = 2
              fmt.Println(b.ID) // 2

              共享同一份数据
              ✅ 常用于组合、组件设计

              这是 Go 非常核心的设计思想。

              type Speaker interface {
              	Speak()
              }
              type Human struct{}
              func (h Human) Speak() {
              	fmt.Println("human speak")
              }
              type Student struct {
              	Human
              }
              var s Speaker = Student{} // ✅ Student 自动实现 Speaker
              s.Speak()
              

              📌 只要嵌入的结构体实现了接口,外层结构体也实现了接口

              type MyInt int
              type Counter struct {
              	MyInt
              }
              c := Counter{}
              c.MyInt = 10
              

              ⚠️ 不如结构体嵌入常见,但合法

              对比项 嵌入结构体 普通字段
              访问方式 u.ID u.Base.ID
              方法提升
              接口继承
              语义 组合 拥有

              📌 推荐原则
              👉 想复用行为(方法) → 用嵌入
              👉 只是数据成员 → 用普通字段

              type Model struct {
              	ID        uint
              	CreatedAt time.Time
              	UpdatedAt time.Time
              }
              type Order struct {
              	Model
              	OrderNo string
              }

              (GORM 就大量用这个模式)

              type Service struct {
              	*Logger
              	*DB
              }
              

              • 以为是继承(不是)
              • ❌ 字段冲突没处理
              • ❌ 不理解指针嵌入 vs 值嵌入
              • ❌ 滥用嵌入(嵌太多层可读性差)

              到此这篇关于go语言中的结构体嵌入详解的文章就介绍到这了,更多相关go语言结构体嵌入内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

              您可能感兴趣的文章:

              • Go语言创建结构体实例对象的几种常用方式
              • go语言中空结构体的实现
              • go中结构体切片的实现示例
              • Go 数据库查询与结构体映射的示例详解
              • 详解Go语言中空结构体的惯用法
              • GO语言中ni,零值与空结构体的使用
              • go语言中嵌套结构体的实现
              • 简单聊聊Go语言中空结构体和空字符串的特殊之处

              站内搜索