- 原文: https://research.swtch.com/interfaces
## Usage
```go
type Stringer interface {
String() string
}
type Binary uint64
func (i Binary) String() string {
return strconv.Uitob64(i.Get(), 2)
}
func (i Binary) Get() uint64 {
return uint64(i)
}
```
- Binary 新类型实现了 Stringer 接口。
## Interface Values
- interface 的值有两个字长值(指针)组成:
- 一个指针,指向存储的类型信息,interface table or itable。
- 一个指针,指向实际的数据(concrete type)。
<img src="https://img.jonahgao.com/oss/note/2025p1/golang_iface_struct.png" width="486" height="238" />
- **itable**
- 包含了类型信息和函数指针。
- 函数指针只包含 interface 的方法,例如 Binary 的 Add 方法就没有在内。
- **data pointer**
- 指向实际的数据,本例中指向的是 b 的一份拷贝。
- `var s Stringer = b` 制作了 b 的一份拷贝,而非指针。
- 执行 type switch 时,检查 `s.itable->type` 是否是目标类型。
- 执行 `s.String()` 时,等价于`s.itable->fun[0](s.data)`。
## Computing the Itable
- itable 里的值是在**运行时**计算的。
1. compiler 为每一个 concrete type 生成了一个 type description structure,其中包含了该类型的 method list。
2. compiler 也为每一个 interface type 生成了 type description structure,结构不同,但是也包含了它的 method list。
3. 当对一个 interface 赋值时,开始计算它的 itable,根据 interface type 的 method list 去查找 concrete type 的 method list。
- 每次生成 itable 后 runtime 会进行缓存,所以只需要计算一次。
## Memory Optimizations
- 如果 interface 类型没有 method,例如 `interface{}`,不分配函数指针部分的内存。
- 一个 interface 是否包含方法可以在静态期判断,从源码层面。
- <img src="https://img.jonahgao.com/oss/note/2025p1/golang_iface_without_method.png" height="170" />
- 如果 concrete type 很小,可以直接放在 interface 中,不需要额外增加一个指针,避免 indirect。
- <img src="https://img.jonahgao.com/oss/note/2025p1/golang_iface_direct.png" width="418" height="238" />