首页 / Go 语言入门教程 / 空接口与 any

Go 语言入门教程

空接口与 any

本教程共 80 篇 · 第 44 篇 · 更新于 2026-07-27 · 约 6 分钟阅读

GoGo 入门教程空接口anyinterface{}类型别名

44. 空接口与 any

本节目标:搞懂空接口是什么,学会用 any 替代 interface{},知道空接口的适用场景和陷阱。

空接口是什么

空接口就是没有任何方法的接口:

type Empty interface{}

因为空接口没有任何方法,所有类型都自动满足它。这意味着空接口变量能存任何类型的值:

package main

import "fmt"

func main() {
    var v interface{}

    v = 42
    fmt.Println(v) // 42

    v = "hello"
    fmt.Println(v) // hello

    v = []int{1, 2, 3}
    fmt.Println(v) // [1 2 3]

    v = struct{ Name string }{"Alice"}
    fmt.Println(v) // {Alice}
}

any 是 interface{} 的别名

Go 1.18 引入了 any 关键字,它是 interface{} 的类型别名:

// Go 源码里的定义
type any = interface{}

两者完全等价,用哪个都行:

// 老写法
func Print(v interface{}) {
    fmt.Println(v)
}

// 新写法(Go 1.18+)
func Print(v any) {
    fmt.Println(v)
}
Tip

从 Go 1.18 开始,推荐用 any 替代 interface{}。更短、更易读,官方文档和标准库已经全面切换到 any

空接口的用途

接收任意类型的参数

当函数需要接收任意类型的参数时,用 any

func Println(v any) {
    fmt.Println(v)
}

Println(42)
Println("hello")
Println(true)

标准库的 fmt.Println 就是用 any 接收参数的:

func Println(a ...any) (n int, err error)

存储任意类型的集合

// 混合类型的列表
list := []any{42, "hello", true, 3.14}

for _, v := range list {
    fmt.Printf("%T: %v\n", v, v)
}
// int: 42
// string: hello
// bool: true
// float64: 3.14

map 存任意值

// key 和 value 都是任意类型
data := map[string]any{
    "name": "Alice",
    "age":  30,
    "scores": []int{90, 85, 88},
}

JSON 解析时经常遇到这种结构,encoding/json 把未知结构的 JSON 解析成 map[string]any

从空接口取值

空接口存了值之后,取出来用需要类型断言:

package main

import "fmt"

func main() {
    var v any = "hello"

    // 取值需要类型断言
    s, ok := v.(string)
    if ok {
        fmt.Println(s) // hello
    }
}
Warning

不能直接对空接口变量做类型特定的操作。比如 v 存的是 string,但你不能直接 len(v),编译器不知道 v 是什么类型。必须先断言。

var v any = "hello"
// fmt.Println(len(v))  // 编译错误
fmt.Println(len(v.(string))) // 5  先断言再操作

空接口的陷阱

丢失类型安全

any 意味着编译器不再帮你检查类型,bug 要到运行时才暴露:

// 用 any,编译器不检查类型
func add(a, b any) any {
    return a.(int) + b.(int) // 如果传的不是int就panic
}

add(1, 2)        // 3
add(1, "hello")  // panic!

比较的坑

空接口可以比较,但如果底层类型不可比较会 panic:

var a any = []int{1, 2}
var b any = []int{1, 2}
fmt.Println(a == b) // panic: runtime error: comparing uncomparable type []int
Note

切片、map、函数这些不可比较的类型存到 any 里后,用 == 比较会 panic。如果不确定底层类型,先做类型判断。

什么时候用 any

  • 需要接收任意类型(如 fmt.Println
  • 解析未知结构的 JSON
  • 泛型无法覆盖的场景

什么时候不该用 any:

  • 类型确定时用具体类型,不要图省事用 any
  • 能用泛型解决的不要用 any(泛型有类型安全)
  • 能用接口的不要用 any(接口有语义约束)
Tip

Go 1.18 以后,很多以前用空接口的场景可以用泛型替代。泛型既保留了通用性,又有编译期类型检查。后面泛型章节会详细讲。

小结

空接口和 any 的要点:

  • anyinterface{} 的别名(Go 1.18+),推荐用 any
  • 空接口能存任何类型的值
  • 取值需要类型断言
  • 用空接口会丢失类型安全,能用泛型就用泛型

下一章讲接口的组合与嵌入。