
在 go 中,通过在子结构体中定义同名方法并显式调用嵌入父结构体的方法(如 `b.base.set(i)`),安全地“重写”嵌入结构体的方法,既保留原有逻辑,又添加新行为(如状态标记),且不破坏 `base` 的独立性。
Go 并不支持传统面向对象语言中的继承或多态,但通过结构体嵌入(embedding) 和方法重定义(method shadowing),可以模拟类似“方法重写”的行为。关键在于:当子结构体 Sub 嵌入 Base 后,若 Sub 自行实现了与 Base 同签名的方法(如 Set(i int)),该方法会遮蔽(shadow) Base 的原方法;但你仍可在 Sub.Set 内部显式调用 b.Base.Set(i) —— 这正是 Go 提供的、等效于其他语言中 super.Set() 的机制。
以下是一个完整、可运行的示例:
package main
import "fmt"
type Base struct {
val int
}
func (b *Base) Set(i int) {
b.val = i
}
type Sub struct {
Base
changed bool
}
// ✅ 正确做法:在 Sub.Set 中调用 Base.Set 并追加逻辑
func (s *Sub) Set(i int) {
s.Base.Set(i) // 显式委托给嵌入结构体方法
s.changed = true
}
func main() {
s := &Sub{}
// 用户像使用 *Base 一样调用 s.Set —— 行为被增强
s.Set(10)
// 验证:Base 字段已更新,且 Sub 状态被标记
fmt.Printf("Base view: %+v\n", &s.Base) // &{val:10}
fmt.Printf("Sub view: %+v\n", s) // &{Base:{val:10} changed:true}
}? 重要说明: 若直接写 s.Base.Set(10),则绕过了 Sub.Set,changed 不会被置为 true; 若希望外部用户「无感知地」使用 Sub 替代 *Base(例如传入期望 *Base 的函数),应确保所有交互都通过 Sub 的方法入口(即 s.Set),而非降级访问 s.Base; Sub 本身*不实现 `Base接口**(除非显式定义),因此不能直接赋值给Base类型变量并期望调用Sub.Set—— Go 中类型严格,Sub和*Base是不同类型。若需接口抽象,建议定义Setter` 接口并让两者实现它。
✅ 总结:Go 中“方法重写”的本质是组合 + 显式委托。它比继承更可控、更清晰,也完全避免了对原 Base 结构体的任何修改,真正做到了“不侵入、可扩展、易测试”。










