Skip to main content

Go: Interface 接口

📅 2026-02-05 ✏️ 2026-03-18 CS GO

1 · Go: Interface 接口#

An interface type defines a type set.

接口类型定义了一个类型集。 接口类型值,可以存储类型集中任一类型的值,是一种类型。

  1. 用作普通类型:在运行时装一个具体值,并动态分发方法;这种接口只能是方法集
  2. 用作泛型参数约束:在编译期约束参数的类型

没有泛型时,这个类型集,可以看作一组方法的签名,所有满足这些方法的类型,都属于这个类型集。 这是Go接口的优点之一:隐式接口,实现了接口的所有方法的类型就隐式地实现了接口。

有泛型后,接口承担起对类型的约束,这个类型集(多个类型的并集),就是约束了类型的范围。 类型集中可以是具体类型TypeTerm,也可以是底层类型~Type。详细见泛型

总结:Go 的接口是静态的(编译时检查)和动态的(运行时动态分发)的结合体。

1.1 · 静态、动态

静态:

  • 检查某个具体类型是否实现接口
  • 检查赋值、传参、返回值是否满足接口
  • 作为泛型约束,限制类型参数的类型集合

动态:

  • 接口值在运行时保存具体动态类型和值
  • 通过接口方法调用发生动态分发
  • 可做类型断言type switch 查询实际类型

1.2 · 编译期与反射

程序里用到的类型,编译期会生成对应的类型元数据; 运行时当一个值被装进接口时,接口值会带上一个指向该具体类型元数据的指针,以及该值的数据表示;

反射就是在程序里使用这些类型元数据。

1.3 · 运行时底层表示

接口值由两个字组成:

┌─────────────────┬─────────────────┐
│   itable 指针   │    数据指针     │
└─────────────────┴─────────────────┘

itable 包含:

  1. 类型元数据
  2. 函数指针列表

重要特性: itable 对应的是接口类型 + 动态具体类型这一对组合,而不是只对应接口类型。

// runtime.iface
type iface struct {
	tab  *itab          // 重要:包含接口类型、具体类型,还有具体类型对该接口各方法的实现入口
	data unsafe.Pointer // 原始数据
}

1.3.1 · 特殊 interface#

对于 interface{}any (无方法),运行时表示里没有 itab,第一字直接保存具体类型指针:

┌──────────────┬──────────────┐
│  类型指针    │  数据指针    │
└──────────────┴──────────────┘
// runtime.eface 在 Go 语言中很常见,实现时使用了特殊的类型
type eface struct {
	_type *_type         // 底层数据类型
	data  unsafe.Pointer // 底层数据
}

1.3.2 · 设计缺陷?

  • 未初始化的接口值是 nil
  • 但如果接口值里装的是“具体类型 + 该类型的 nil 值”,那么这个接口值本身不为 nil

接口与具体实现分离, 依赖一个约定好的接口

1.4 · 方法动态派发

调用接口的方法,在编译期间不能确定接口的具体类型(编译器优化:去虚化),那么在运行期间决定调用该方法的哪个实现;

接口类型调用,运行时动态派发; 具体类型调用,编译期确定;使用 -N 关闭编译器优化

获取 itab->fun[0] 到寄存器,iface 的 data 作为接收者参数放到寄存器,通过 CALL 间接调用

2 · links#

https://go.dev/ref/spec#Interface_types

https://research.swtch.com/interfaces

3 · issue#

  1. #21670 函数自动实现同签名单方法接口
  2. #47487 允许显式转换 I(f)
  3. #48288 struct 里的函数字段进入 method set