type switch仅适用于interface{}等接口类型,不能用于int、string等具体类型;每个case只能匹配一种类型(不可并列),需显式处理nil及指针/值类型差异。

type switch 不是万能类型判断工具,它只对 interface{} 类型有效,且不能嵌套或混用值匹配。
type switch 只能用于接口变量
如果你对一个 int、string 或结构体变量直接写 switch v := x.(type),编译器会报错:invalid type assertion: x.(type) (non-interface type int on left)。Go 要求左侧必须是接口类型,最常见的是 interface{}。
典型误用场景:
- 从 JSON 解析得到
map[string]interface{}后,想判断某个 value 是int还是float64→ ✅ 合法,value 是interface{} - 函数参数是
func handle(n int),内部却写switch n.(type)→ ❌ 编译失败,n是具体类型,不是接口 - 用
reflect.TypeOf(x).Kind()替代 type switch → 可行但更重,且失去编译期类型安全
case 中不能并列多个类型
你不能写 case int, string: 这样的语法 —— Go 会直接报错:invalid case int,string in type switch。每个 case 只能跟一个类型(或 nil)。
正确做法是分开写,或提取公共逻辑:
switch v := data.(type) {
case int:
handleNumber(v)
case int8:
handleNumber(int(v))
case int16:
handleNumber(int(v))
case float64:
handleNumber(int(v))
default:
log.Printf("unhandled type: %T", v)
}
注意:int 和 int64 是不同类型,不会自动转换;json.Unmarshal 默认把数字转成 float64,这点常被忽略。
指针类型和值类型要分开写 case
接口里存的是 *string 还是 string,是两个完全不同的动态类型。写 case string: 匹配不到 *string,反之亦然。
常见陷阱:
- 传入
&s(*string),但只写了case string:→ 落入default - 结构体实现接口时用了值接收器,但接口变量实际存的是指针 → 动态类型是
*MyStruct,不是MyStruct - 想统一处理所有字符串相关类型(
string、*string、[]byte)→ 必须分 case,或提前做归一化(如都转成string)
nil 接口值必须显式用 case nil 处理
接口变量为 nil 时,它的动态类型和动态值都是 nil,但 case nil: 是唯一能捕获它的分支。不写这个 case,nil 会掉进 default,容易引发空指针 panic。
示例:
var data interface{} = nil
switch v := data.(type) {
case string:
fmt.Println("string:", v)
case int:
fmt.Println("int:", v)
case nil:
fmt.Println("data is nil") // 必须显式写这一行
default:
fmt.Printf("other: %T\n", v)
}
另外,case nil 分支里的 v 类型仍是 interface{},不能直接当具体类型用 —— 它就是个空接口的空值。
真正难处理的不是语法,而是动态类型的“隐式性”:同一个接口变量在不同调用路径中可能存 int、float64、*User 甚至 nil,而这些信息只在运行时才确定。type switch 是 Go 提供的最轻量、最安全的应对方式,但前提是得清楚知道——你在判断的从来不是变量声明类型,而是它此刻“装了什么”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











