
通过定义统一接口(如 Lengther)并让不同结构体实现其方法,可将多个类型专属函数合并为单一泛化函数,提升代码复用性与可维护性。
通过定义统一接口(如 `lengther`)并让不同结构体实现其方法,可将多个类型专属函数合并为单一泛化函数,提升代码复用性与可维护性。
在 Go 语言中,若需对多种结构体(如 AA 和 BB)执行相同逻辑(例如获取内部切片长度),不应为每种类型编写独立函数,而应借助接口抽象实现多态行为。核心思路是:提取共性操作为接口方法,让各结构体实现该方法,再通过接口参数统一调用。
✅ 正确做法:基于接口的泛化设计
首先定义一个只含 Length() int 方法的接口:
type Lengther interface {
Length() int
}
接着,为 AA 和 BB 分别实现该方法——注意需使用指针接收者(因后续常以地址传递,且符合方法集一致性):
func (a *AA) Length() int {
return len(a.ids)
}
func (b *BB) Length() int {
return len(b.ids)
}
最后,编写唯一通用函数,参数类型为接口:
func length(l Lengther) int {
return l.Length()
}
完整可运行示例:
package main
import "fmt"
type Lengther interface {
Length() int
}
type A struct { id string }
type AA struct { ids []A }
func (a *AA) Length() int { return len(a.ids) }
type B struct { id string; value bool }
type BB struct { ids []B }
func (b *BB) Length() int { return len(b.ids) }
func length(l Lengther) int {
return l.Length()
}
func main() {
aa := &AA{ids: make([]A, 10)}
bb := &BB{ids: make([]B, 34)}
fmt.Println(length(aa)) // 输出: 10
fmt.Println(length(bb)) // 输出: 34
}
⚠️ 注意事项
- 接收者类型需一致:若使用值接收者(如 func (a AA) Length()),则 AA{} 可满足接口,但 &AA{} 同样可以;而指针接收者更常见于修改状态或避免复制大结构体。本例中推荐指针接收者,因 AA/BB 通常作为复合结构被引用。
- 接口最小化原则:Lengther 仅包含必要方法,符合 Go 的“小接口”哲学,利于组合与测试。
- 不可直接传值调用:若函数期望 *AA 而传入 AA{},会编译失败;务必确保调用方传递的是满足接口的具体类型实例(如 &AA{} 或已声明的指针变量)。
- 扩展性强:未来新增 CC 类型时,只需实现 Length() 方法即可无缝接入 length() 函数,无需修改原有逻辑。
这种设计不仅解决了函数重复问题,更体现了 Go “组合优于继承”和“接口即契约”的核心思想,是构建清晰、可演进 API 的推荐实践。











