Go 入门(08):类型断言与类型 switch——从空接口里取回具体值
更新时间:2026-09-01。本文是
languages/go/beginner/入门层第 8 篇,接 接口。接口存的是"值+类型",从接口里取出具体类型的值叫类型断言。本篇讲两种用法:安全断言和类型 switch。
本文要回答的问题
- 类型断言怎么用?
v, ok := i.(T)的 ok 是什么? - 不用 ok 会怎样?panic 还是 nil?
- 类型 switch 和普通 switch 的区别是什么?
- 什么时候用类型断言,什么时候用类型 switch?
一、类型断言:从接口取回具体值
go
var i interface{} = 42
// 安全断言(推荐):带 ok 判断
v, ok := i.(int)
if ok {
fmt.Println("是 int:", v)
} else {
fmt.Println("不是 int")
}
// 不安全断言(不推荐):不分检查,错了直接 panic
v2 := i.(int) // 安全,因为 i 确实是 int
v3 := i.(string) // panic!i 是 int,不是 string安全断言:v, ok := i.(具体类型),ok 表示是否成功,成功就取回值,不成功 v 是零值,不会 panic。
不安全断言:v := i.(具体类型),类型不对直接 panic。
二、类型 switch:匹配多个类型
当你不知道接口里是什么类型,或者可能有好几种类型,用类型 switch:
go
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("int: %d\n", v)
case string:
fmt.Printf("string: %s\n", len(v))
case bool:
fmt.Printf("bool: %v\n", v)
default:
fmt.Printf("unknown type: %T\n", v)
}
}语法注意:
i.(type)只能用在 switch 里,不能用在别处v在每个 case 里自动转换成对应类型default处理没列出的类型
%T 是格式化打印类型名的技巧:
go
fmt.Printf("type is %T\n", i) // 打印类型名三、类型断言的实际场景
场景 1:处理错误类型
go
_, err := openFile("not-exist.txt")
if e, ok := err.(*os.PathError); ok {
fmt.Printf("path error: %s, op=%s\n", e.Path, e.Op)
}场景 2:判断接口实现
go
type Stringer interface {
String() string
}
var i interface{} = 42
if s, ok := i.(Stringer); ok {
fmt.Println(s.String())
} else {
fmt.Println("不是 Stringer")
}场景 3:JSON 反序列化后取数据
go
var data interface{}
json.Unmarshal([]byte(`{"name":"Alice", "age":25}`), &data)
m := data.(map[string]interface{})
name := m["name"].(string) // "Alice"
age := m["age"].(float64) // JSON 数字默认是 float64四、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 不安全断言 | 类型不对直接 panic | 永远用 v, ok := i.(T) 安全断言 |
| 类型 switch 里忘了 default | 没匹配的类型直接跳过,不报错 | 加 default 分支兜底 |
| JSON 数字断言成 int | panic,因为 JSON 数字是 float64 | 先断言成 float64 再转 int |
| 对 nil 接口断言 | 类型是 nil,断言失败 | 先判断接口本身不是 nil |
相关与延伸
下一篇:包与模块管理——go.mod、import、导出规则;类型断言底层是运行时检查 itab,进阶层会讲接口的内部实现;JSON 处理见 JSON 序列化。
一句话总结
类型断言:v, ok := i.(T) 从接口取回具体类型,安全断言永远用 ok 检查;i.(type) 只能在 switch 里用,用来匹配多个类型;不安全断言 v := i.(T) 类型不对直接 panic,别用;JSON 数字断言出来是 float64,不是 int。