← Backend / Go / 基础专题

18_接口与隐式实现

理解接口描述行为、实现不需声明,以及接口值的组成。

Go 基础专题 18:接口与隐式实现

学习目标:理解接口描述行为、实现不需声明,以及接口值的组成。

核心知识

接口列出一组方法;只要类型具有这些方法,就自动满足接口,不需要 implements 关键字。接口适合由使用方定义最小能力,而不是把所有方法堆成一个大接口。常见的 io.Reader 只需 Read(p []byte) (n int, err error)。

package main

import "fmt"

type Speaker interface { Speak() string }
type Dog struct{}
func (Dog) Speak() string { return "汪" }

func announce(s Speaker) { fmt.Println(s.Speak()) }
func main() { announce(Dog{}) }

接口值包含动态类型和动态值。一个保存了“类型为 *Dog、值为 nil”的接口本身不等于 nil,这是常见陷阱;返回接口时不要把带类型的 nil 指针当作无错误值。any 是空接口的别名,可容纳任何类型,但滥用会失去静态检查收益。

方法集决定是否满足接口:指针接收者的方法通常只属于 *T 的方法集,因此 T 与 *T 对接口的实现可能不同。接口用于行为抽象,数据传输结构体一般不必先抽象成接口。

逐步理解

从使用方角度看,announce 只依赖 Speak,不需要知道 Dog 的字段。把接口缩小到最少的方法,测试替身也更容易实现。注意接口中装入“带类型的 nil 指针”仍不是 nil;要避免将其作为成功结果返回,尤其是返回 error 接口时。

动手练习

练习:让 Cat 实现 Speak() string,传给 announce。答案要点:无需修改 Speaker 声明。