恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
8.3 Go Struct 嵌入学习笔记
首页
资讯中心
/
8.3 Go Struct 嵌入学习笔记
8.3 Go Struct 嵌入学习笔记
发布时间:2026/9/2 8:02:40
8.3 Go Struct 嵌入学习笔记1. 结构体嵌入匿名嵌入Go 没有类的继承但可以通过匿名嵌入一个结构体来获得组合能力typeEnginestruct{HorsepowerintTypestring}func(e Engine)Start(){fmt.Printf(Starting %s engine with %d HP\n,e.Type,e.Horsepower)}func(e Engine)Stop(){fmt.Printf(Stopping %s engine\n,e.Type)}typeCarstruct{MakestringModelstringYearintEngine// 匿名嵌入 Engine没有字段名}匿名嵌入 vs 具名嵌入结构体嵌入有两种写法匿名嵌入嵌入式— 不写字段名方法提升typeCarstruct{MakestringEngine// 不写字段名}// 访问car.Start()、car.Horsepower字段和方法自动提升具名嵌入普通字段— 写字段名没有提升typeCarstruct{MakestringMotor Engine// 写字段名}// 访问car.Motor.Start()、car.Motor.Horsepower必须通过字段名区别匿名嵌入具名嵌入写法EngineMotor Engine字段访问car.Horsepower提升car.Motor.Horsepower方法访问car.Start()提升car.Motor.Start()接口实现外层自动满足嵌入类型的接口外层不自动满足匿名嵌入的核心优势是方法提升——嵌入类型的字段和方法可以直接在外层使用。具名嵌入则没有任何提升效果只是普通的结构体字段。嵌入后 Car 可以直接访问 Engine 的字段和方法car:Car{Make:Toyota,Model:Camry,Year:2023,Engine:Engine{Horsepower:200,Type:V6},}car.Stop()// 直接调用 Engine 的 Stop 方法字段提升car.Engine.Start()// 也可以显式通过 Engine 访问执行结果Stopping V6 engine Starting V6 engine with 200 HP要点匿名嵌入不需要字段名Go 自动用类型名作为字段名Engine嵌入的字段和方法会提升到外层结构体。2. 方法提升与覆盖当外层结构体和嵌入结构体有同名方法时外层的方法会覆盖嵌入的方法// Engine 的 Start 方法func(e Engine)Start(){fmt.Printf(Starting %s engine with %d HP\n,e.Type,e.Horsepower)}// Car 的 Start 方法 — 覆盖了 Engine 的 Startfunc(c Car)Start(){fmt.Printf(Starting %d %s %s\n,c.Year,c.Make,c.Model)c.Engine.Start()// 在覆盖方法中显式调用嵌入的方法}调用结果car.Start()// 调用 Car 的 Start覆盖版本car.Engine.Start()// 显式调用 Engine 的 Start原始版本执行结果Starting 2023 Toyota Camry ← Car.Start() 覆盖方法 Starting V6 engine with 200 HP ← Car.Start() 中显式调用了 Engine.Start() Starting V6 engine with 200 HP ← car.Engine.Start() 直接调用要点car.Start()→ 调用 Car 自己的 Start覆盖car.Engine.Start()→ 调用 Engine 的 Start原始覆盖方法中可以用c.Engine.Start()调用被覆盖的方法类似其他语言的super3. 多层嵌入结构体可以嵌入多层方法会逐层提升typeLuxuryCarstruct{Car// 嵌入 CarCar 里又嵌入了 EngineGPS// 嵌入 GPSRadio// 嵌入 RadioLeatherSeatsbool}LuxuryCar 可以直接调用所有嵌入层的方法luxuryCar:LuxuryCar{Car:Car{Make:BMW,Model:X7,Year:2024,Engine:Engine{Horsepower:400,Type:V8},},GPS:GPS{Brand:Garmin,HasMaps:true},Radio:Radio{Brand:Bose,HasBluetooth:true},LeatherSeats:true,}luxuryCar.Start()// Car 的 Start覆盖了 Engine 的 StartluxuryCar.Drive()// Car 的 DriveluxuryCar.Navigate(Downtown)// GPS 的 NavigateluxuryCar.PlayMusic()// Radio 的 PlayMusic执行结果Starting 2024 BMW X7 Starting V8 engine with 400 HP Driving 2024 BMW X7 Garmin GPS navigating to Downtown Playing music on Bose radio要点嵌入链 Car → Engine → Start/StopLuxuryCar → Car → Drive/StartLuxuryCar 可以直接调用所有层级提升的方法。4. 字段名冲突当嵌入的多个结构体有同名字段时直接访问会编译报错必须显式指定typePersonstruct{NamestringAgeint}typeCompanystruct{NamestringEmployeesint}typeEmployeestruct{IDintPositionstringPerson// 嵌入 Person有 Name 字段Company// 嵌入 Company也有 Name 字段}Person和Company都有Name字段产生冲突// emp.Name ← 编译错误ambiguous field Name// 必须显式指定emp.Person.Name// John Doeemp.Company.Name// Tech Corp完整访问示例emp:Employee{ID:1001,Position:Software Engineer,Person:Person{Name:John Doe,Age:30},Company:Company{Name:Tech Corp,Employees:500},}fmt.Printf(Employee: %s (ID: %d)\n,emp.Person.Name,emp.ID)fmt.Printf(Works at: %s\n,emp.Company.Name)fmt.Printf(Age: %d\n,emp.Person.Age)执行结果Employee: John Doe (ID: 1001) Works at: Tech Corp Position: Software Engineer Age: 30要点字段冲突时不能直接用emp.Name必须用emp.Person.Name或emp.Company.Name显式指定来源。5. 嵌入与接口嵌入的结构体方法也会被提升到外层使得外层结构体自动实现嵌入结构体所满足的接口// Car 嵌入了 Engine所以 Car 也拥有 Engine 的所有方法// 如果某个接口要求 Start() 和 Stop()Engine 满足的话 Car 也满足varengine Enginecar.Engine// 提取嵌入的结构体engine.Start()执行结果Starting V6 engine with 200 HP要点嵌入不是继承但可以实现类似接口继承的效果——嵌入结构体满足的接口外层结构体也自动满足。6. 嵌入 vs 继承Go 的嵌入与传统继承的关键区别继承Java/C嵌入Go关系子类是父类的一种is-a组合关系has-a但方法可提升类型子类可以赋值给父类变量外层结构体不能赋值给嵌入类型变量方法覆盖子类覆盖父类方法外层方法覆盖嵌入方法但可以显式调用嵌入版本多态通过继承实现通过接口实现// ❌ 不可以这样赋值// var eng Engine car // 编译错误Car 不是 Engine// ✅ 只能提取嵌入的结构体vareng Enginecar.Engine// 正确知识点总结知识点关键概念匿名嵌入不写字段名Go 用类型名作为字段名字段和方法自动提升方法提升嵌入结构体的方法可以直接在外层调用方法覆盖外层同名方法覆盖嵌入方法可用c.EmbedType.Method()显式调用多层嵌入嵌入链逐层提升LuxuryCar 可调用 Engine、Car、GPS、Radio 的方法字段冲突多个嵌入有同名字段时必须显式指定来源emp.Person.Name接口提升嵌入结构体满足的接口外层也自动满足嵌入≠继承Car 不能赋值给 Engine 变量组合而非 is-a 关系