>

##### 简介 --- Go 语言中的 interface 关键字可以用来定义一个接口类型,里面声明一些方法,也可以当做任意类型,那么 interface 类型的底层是怎么实现的呢? 其实早在 2009 年,Russ Cox 就写过一篇[文章][] 来解释 interface 类型的值在 Go 语言中底层是如何描述的。

那篇文章虽然非常经典,但是看完之后可能还是不够过瘾。因此,这篇文章将会试图从源码的层面来抽丝剥茧,解析 interface 在底层到底是如何实现和运作的。

实际上,一个interface 类型的变量底层用了一个 struct 来存储了一对 (type, value) ,变量的类型会赋给 type,而具体的变量的值则会赋给value,
这样的话,这个 interface{} 类型的变量就保存了原始类型的完整信息。

通过查看源码声明(如下)会发现 inteface 底层用了一个 interface header,用一个结构体来保存这个对象:

1
2
3
4
5
// ifaceWords is interface{} internal representation.
type ifaceWords struct {
typ unsafe.Pointer
data unsafe.Pointer
}

可见是两个指针成员,一个指向类型,一个指向实体。

由于 Pointer 是 uintptr 类型,在 64 位机器上是 8 字节大小,所以,当把一个 int 类型的值传递给一个接受 interface{} 类型的函数做参数时,内存空间会增加一倍。

提示:在 Go 语言中,[]byte 默认是 24 字节大小, string 16 字节大小。


##### 如何 indirect (解引用)一个 interface{} 类型 ? ---

首先拿到它的 reflect.value, 我们设为 v
判断 v 是否是指针类型? 是否一个 named type:
If v is a named type and is addressable,(也即 v.CanAddr()) start with its address, so that if the type has pointer methods。

解释一下什么叫做 addressable, addressable 的意思就是这个 value 是可以寻址的,
也就是说要解析的这个值必须是这个值本身,而不是它的一个拷贝,或者一个临时变量。
比如: 在作为函数参数传递时,如果传递的是值传递, 而不是指针,或者传了个临时变量, 那么 就不是 addressable 的了。
这个特点有点类似于 settable 这个特性。 如果是传了一个 拷贝,那么也不是settable 的, 必须传指针才行。
Settability is a bit like addressability, but stricter. 而且,只有 struct 的 field 是大写,exported, 这个field才是 settable的。

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println(“type of p:”, p.Type())
p 本身不是 settable 的, 因为 p 是一个指向实际对象的指针, p 指向的对象才是 settable 的。
To get to what p points to, we call the Elem method of Value, which indirects through the pointer, and save the result in a reflection Value called v:
v := p.Elem()
fmt.Println(“settability of v:”, v.CanSet())

如果是一个 named type, 那么我们就取得它的地址: v = v.Addr()

因为要 set 这个 named type 的值, 所以我们需要取得该指针指向的真实对象: v = v.Elem()

我们还需要递归解析 v 的值,




Reference

http://shanks.leanote.com/post/Untitled-55ca439338f41148cd000759-17