接口类型 interface 是由一组方法签名定义的集合。
接口类型的值可以保存任何实现了这些方法的值。
在内部,接口值可以看做包含值和具体类型的元组:(value, type)
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
指定了零个方法的接口值被称为 空接口:interface{}
空接口被用来处理未知类型的值。
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)
", i, i)
}
类型断言 提供了访问接口值底层具体值的方式。
t := i.(T) 该语句断言接口值i
保存了具体类型T
,并将其底层类型为T
的值赋予变量t
。若i
并未保存T
类型的值,该语句就会触发一个恐慌。
为了 判断 一个接口值是否保存了一个特定的类型, 类型断言可返回两个值:其底层值以及一个报告断言是否成功的布尔值。
t, ok := i.(T)若i
保存了一个T
,那么t
将会是其底层值,而ok
为true
。否则,ok
将为false
而t
将为T
类型的零值,程序并不会产生恐慌。
类型选择 是一种按顺序从几个类型断言中选择分支的结构。
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v ", v, v*2)
case string:
fmt.Printf("%q is %v bytes long ", v, len(v))
default:
fmt.Printf("I don't know about type %T! ", v)
}
}