雨痕 Go语言学习笔记-接口

接口

  1. 接⼝命名习惯以 er 结尾,结构体
  2. 接⼝没有数据字段
  3. 可在接⼝中嵌⼊其他接⼝

执行机制

  1. 接⼝对象由接⼝表 (interface table) 指针和数据指针组成
  2. 接⼝表存储元数据信息,包括接⼝类型、动态类型,以及实现接⼝的⽅法指针。⽆论是反

    射还是通过接⼝调⽤⽅法,都会⽤到这些信息
  3. 数据指针持有的是目标对象的只读复制品(不能修改),复制完整对象或指针
  4. 接⼝转型返回临时对象,只有使⽤指针才能修改其状态
type User struct {
 id int
 name string
}
func main() {
 u := User{1, "Tom"}
 var vi, pi interface{} = u, &u
 // vi.(User).name = "Jack" // Error: cannot assign to vi.(User).name
 pi.(*User).name = "Jack"
 fmt.Printf("%v\n", vi.(User))
 fmt.Printf("%v\n", pi.(*User))
}
输出:
{1 Tom}
&{1 Jack}
  1. 只有 tab 和 data 都为 nil 时,接⼝才等于 nil。(另一种解释,接口底层包含两个数据结构,一个指带接口类型,一个指带数据。只有类型和数据都为空时,接口才为空)
var a interface{} = nil // tab = nil, data = nil
var b interface{} = (*int)(nil) // tab 包含 *int 类型信息, data = nil
type iface struct {
 itab, data uintptr
}
ia := *(*iface)(unsafe.Pointer(&a))
ib := *(*iface)(unsafe.Pointer(&b))
fmt.Println(a == nil, ia)
fmt.Println(b == nil, ib, reflect.ValueOf(b).IsNil())
输出:
true {0 0}
false {505728 0} true

接⼝技巧

  1. 让编译器检查,以确保某个类型实现接⼝。
var _ fmt.Stringer = (*Date)(nil) // nil指interface{},转换成*Date

总结

  1. 接口内部存储结构,接口为空的判断
  2. 接口类型转换
  3. 接口技巧
comments powered by Disqus