接口
Go 的接口是隐式实现的:只要类型实现了接口的所有方法,就自动满足该接口,无需 implements 关键字。
接口定义
1 2 3 4 5 6 7
| type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
|
隐式实现
1 2 3 4 5 6 7 8 9 10 11
| type File struct { path string }
func (f *File) Read(p []byte) (int, error) { return 0, nil }
var r Reader = &File{path: "data.txt"}
|
空接口
interface{}(Go 1.18+ 可写 any)不包含任何方法,所有类型都实现空接口:
1 2 3 4 5 6 7
| func printAny(v any) { fmt.Println(v) }
printAny(42) printAny("hello") printAny([]int{1, 2})
|
类型断言
从 interface 取出具体类型:
1 2 3 4 5 6 7
| var i any = "hello"
s, ok := i.(string) n, ok := i.(int)
s = i.(string)
|
类型 switch:
1 2 3 4 5 6 7 8
| switch v := i.(type) { case string: fmt.Println("string:", v) case int: fmt.Println("int:", v) default: fmt.Println("unknown") }
|
接口组合
1 2 3 4
| type ReadWriter interface { Reader Writer }
|
常用标准接口
| 接口 |
包 |
典型用途 |
io.Reader / io.Writer |
io |
读写抽象 |
fmt.Stringer |
fmt |
自定义 String() 输出 |
error |
builtin |
错误类型 |
sort.Interface |
sort |
自定义排序 |
1 2 3 4 5 6
| type Point struct{ X, Y int }
func (p Point) String() string { return fmt.Sprintf("(%d,%d)", p.X, p.Y) }
|
面向接口编程
依赖接口而非具体类型,便于测试和扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13
| type UserStore interface { Get(id int64) (*User, error) Save(u *User) error }
type Service struct { store UserStore }
func NewService(store UserStore) *Service { return &Service{store: store} }
|
nil 接口陷阱
1 2 3 4 5 6 7 8
| var err error var p *MyError = nil err = p
if err != nil { fmt.Println("not nil") }
|
接口变量为 nil 当且仅当动态类型和动态值都为 nil。
小结
- 接口隐式实现,是 Go 多态的核心
- 小接口 + 组合,优于大而全的接口
- 面向接口编程提升可测试性与扩展性
- 注意 nil 接口的判断陷阱