接口

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.Printlnjson.Marshal 的参数很多都是空接口。拿出来用之前,通常还是要断言回具体类型。

空接口的零值是 nil。注意:一个接口变量,动态类型有了、动态值是 nil 指针时,这个接口值不等于 nil


参考文档