接口
2026年9月6日
接口是一组方法签名。它自己没有实现,也不能再给接口绑方法。一个类型只要实现了接口里的全部方法,就实现了这个接口,不用写 implements。
接口值里存两样东西:动态类型和动态值。
type Speaker interface {
Speak() string
}
type Dog struct{ Name string }
func (d Dog) Speak() string {
return d.Name + ": woof"
}
func greet(s Speaker) {
fmt.Println(s.Speak())
}
greet(Dog{Name: "旺财"})
go
指针接收者实现的方法,只有指针能赋给接口;值接收者则值和指针都可以。
类型断言
接口到手之后,有时还要知道里面到底是什么类型。
var s Speaker = Dog{Name: "旺财"}
d, ok := s.(Dog)
if ok {
fmt.Println(d.Name)
}
go
一个返回值:断言失败会 panic。两个返回值:失败时 ok == false,不会炸。
多种可能用 type switch:
switch v := s.(type) {
case Dog:
fmt.Println("dog", v.Name)
default:
fmt.Printf("other %T\n", v)
}
go
空接口
interface{}(Go 1.18 起也可以写 any)一个方法都没有。任何类型都实现了它,所以能接任意值。
func printAny(v any) {
fmt.Printf("%T %v\n", v, v)
}
printAny(1)
printAny("槿")
printAny(Dog{Name: "旺财"})
go
fmt.Println、json.Marshal 的参数很多都是空接口。拿出来用之前,通常还是要断言回具体类型。
空接口的零值是 nil。注意:一个接口变量,动态类型有了、动态值是 nil 指针时,这个接口值不等于 nil。