Go中string类型不可能为nil,其零值恒为"";判空应统一用s=="",需区分“未设置”与“设为空”时须用*string或sql.NullString等可空封装。

Go 里 string 类型根本不会是 nil
这是最常被误解的一点:Go 的 string 是值类型,不是指针或接口,所以它**不可能为 nil**。你写 var s string,s 就是空字符串 "";传参、返回、结构体字段默认零值,也都是 ""。试图对 string 做 s == nil 判断会编译报错:invalid operation: s == nil (mismatched types string and nil)。
真正需要区分“未设置”和“设为空”的场景,通常得靠指针或可空类型封装:
- 用
*string:func f(s *string) { if s == nil { /* 未传 */ } else if *s == "" { /* 传了但为空 */ } } - 用
sql.NullString(适合数据库交互) - 自定义类型加
Valid bool字段(如 API 请求结构体)
判断空字符串的正确写法只有 s == ""
别用 len(s) == 0 —— 虽然结果一样,但语义不清,且在极少数极端优化场景下有微小开销(len 需读取底层 header)。Go 官方文档和标准库都统一用 == "",保持一致最安全。
常见误判模式:
立即学习“go语言免费学习笔记(深入)”;
-
if s != nil→ 编译失败 -
if s == "" || s == "null" || s == "undefined"→ 这是前端 JS 习惯,后端不该混入业务语义到空值判断里 -
strings.TrimSpace(s) == ""→ 只在你明确需要忽略空白时才用;否则多一次内存分配和遍历,不必要
结构体中 string 字段的“空/未设置”二义性怎么破
比如 API 接收 JSON:{"name": ""} 和 {} 对应同一个 struct 字段 Name string,两者都变成 "",无法区分用户是“想清空”还是“没填”。这时必须改用指针:
type UserReq struct {
Name *string `json:"name,omitempty"`
}
解码后:
-
{"name": ""}→Name指向一个值为""的 string -
{}或{"name": null}→Name == nil
注意:omitempty 只影响序列化,不影响反序列化逻辑;要支持 null,还得确保 JSON 解码器没禁用 UseNumber 等干扰项。
map 和 slice 中的 string 值仍需单独判空
map 的 value 是 string,查不到 key 时得到的是零值 "",不是 nil。所以不能只靠 v, ok := m[k] 后直接用 v,得再判断:
v, ok := m["key"]
if !ok || v == "" {
// 未设置 或 显式设为空
}
slice 也是类似逻辑:if len(ss) == 0 是判 slice 是否为空,但每个元素仍是 string,若要检查所有元素是否全为空,得遍历:allEmpty := true; for _, s := range ss { if s != "" { allEmpty = false; break } }。
真正容易漏掉的点:嵌套结构里,比如 map[string][]string,你得先确认 key 存在、slice 非 nil、再检查长度、最后看元素内容——每层都可能“意外为零”。


















