Go 接口的实现规则

在 Go 语言中,接口的实现规则取决于方法的接收者类型(值接收者 (T) 还是 指针接收者 (*T))。具体规则如下:


1. 值接收者 (T) 实现接口

如果方法使用 值接收者func (t T) Method()),那么:

  • T*T 都算实现了接口(Go 会自动解引用指针)。
  • 赋值给接口时,可以用 T*T

示例

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

// 值接收者
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func main() {
    var s Shape

    // ✅ 可以用 Circle(值类型)
    c1 := Circle{Radius: 5}
    s = c1  // 正确
    fmt.Println(s.Area())

    // ✅ 也可以用 *Circle(指针类型)
    c2 := &Circle{Radius: 10}
    s = c2  // 也正确
    fmt.Println(s.Area())
}

结论:值接收者的方法,T*T 都算实现了接口。


2. 指针接收者 (*T) 实现接口

如果方法使用 指针接收者func (t *T) Method()),那么:

  • 只有 *T 算实现了接口T 不算。
  • 赋值给接口时,必须用 *T,不能用 T(否则编译错误)。

示例

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

// 指针接收者
func (c *Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func main() {
    var s Shape

    // ❌ 不能用 Circle(值类型)
    c1 := Circle{Radius: 5}
    s = c1  // 编译错误:Circle does not implement Shape (Area method has pointer receiver)

    // ✅ 必须用 *Circle(指针类型)
    c2 := &Circle{Radius: 10}
    s = c2  // 正确
    fmt.Println(s.Area())
}

结论:指针接收者的方法,只有 *T 算实现了接口T 不算。


3. 为什么 Go 这样设计?

  • 值接收者 (T)
    • 方法不会修改原对象(因为是副本)。
    • Go 允许 T*T 都实现接口,更灵活。
  • 指针接收者 (*T)
    • 方法可能修改原对象(因为是引用)。
    • 只有 *T 能保证正确的行为,所以 T 不算实现接口。

4. 如何选择接收者类型?

情况 推荐接收者类型
方法不需要修改结构体 值接收者 (T)(更通用)
方法需要修改结构体 指针接收者 (*T)
结构体较大(避免复制开销) 指针接收者 (*T)
需要强制使用指针(如实现接口) 指针接收者 (*T)

5. 总结

方法接收者 实现接口的类型 赋值给接口的方式
(T) Method() T*T var s Shape = T{}var s Shape = &T{}
(*T) Method() *T var s Shape = &T{}(不能用 T{}

记住

  • 值接收者 → 更灵活,T*T 都能用。
  • 指针接收者 → 更严格,只有 *T 能赋值给接口。

这样设计是为了保证代码的安全性和一致性。🚀

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容