go接口是隐式实现的,无需显式声明;只要类型方法集完全匹配接口签名(含导出名、参数、返回值),即自动满足,且指针/值接收者影响满足关系。
Go 接口不需要显式声明“实现”
Go 语言的接口是隐式实现的——只要一个类型的方法集包含接口定义的所有方法签名(名称、参数类型、返回类型完全一致),它就自动满足该接口,无需 implements 或 interface{} 这类关键字声明。
这是 Go 和 Java/C# 最显著的区别之一,也是容易让初学者困惑的地方:不是“我告诉编译器我实现了”,而是“编译器发现你刚好能干这事”。
- 方法名、参数顺序、参数类型、返回值个数与类型必须严格匹配;
int和int64不兼容,[]string和...string也不等价 - 指针接收者和值接收者影响方法集:如果接口方法由
*T实现,则只有*T满足接口;T值本身不自动满足(除非方法也是用T接收) - 空接口
interface{}是特例:任何类型都满足它,因为没方法要实现
为什么 func (t T) String() string 不能让 T 满足 fmt.Stringer?
常见错误是定义了 String() 方法但忘记导出:Go 接口中方法名必须首字母大写(即导出),否则无法被外部包识别。即使你在同一个包里,fmt.Stringer 是标准库接口,它的方法 String() 是导出的,你的实现也必须是导出方法。
- ❌ 错误写法:
func (t T) string() string(小写,未导出)→ 编译通过但不满足fmt.Stringer - ✅ 正确写法:
func (t T) String() string(大写开头) - 注意:是否加
*取决于你想让T还是*T满足接口;fmt.Printf("%v", t)会尝试调用t.String(),若t是值类型而方法是*T接收,则需可寻址(如变量而非字面量)
接口满足关系在编译期检查,但不生成“实现表”
Go 不在运行时维护类型到接口的映射表(不像 JVM 的 vtable 或 .NET 的 interface map)。接口变量底层是 (type, value) 结构体,赋值时才做一次静态方法集检查。这意味着: