Go中string变量绝不可能为nil,其零值恒为"";判空应直接用s == ""或len(s) == 0;*string才需先判nil再解引用,用于区分“字段缺失”与“字段为空字符串”两种语义。

Go里字符串变量根本不会是nil
Go语言中string是值类型,不是指针类型,所以声明但未赋值的string变量默认就是""(空字符串),绝不可能是nil。试图对string做== nil判断会直接编译报错:invalid operation: s == nil (mismatched types string and nil)。
常见误判场景:把*string(指向字符串的指针)当成string本身处理。比如API解码JSON时字段为可选,生成的结构体字段可能是*string,这时才需要先判nil再解引用。
- ✅ 正确判空:
if s == "" - ❌ 编译失败:
if s == nil(s类型为string) - ✅ 指针判空:
if sPtr != nil && *sPtr == ""(sPtr类型为*string)
JSON反序列化中*string字段的空值陷阱
用encoding/json解析含可选字符串字段的JSON时,如果字段缺失或为null,对应*string字段会是nil;如果字段存在但值为空字符串"",则指针非nil且内容为空。这两者语义不同,但容易被统一当作“空”处理,导致业务逻辑出错。
例如用户提交的昵称字段允许为空字符串(表示“不想填”),也允许不提交(表示“未设置”),后端需区分这两种状态。
立即学习“go语言免费学习笔记(深入)”;
- JSON
{"name": null}→name字段为nil - JSON
{"name": ""}→name字段非nil,*name == "" - JSON
{}(无该字段)→name字段也为nil - 判“有效非空”应写:
name != nil && *name != ""
函数参数接收string还是*string?看是否需要表达“未提供”语义
函数设计时,参数类型选择直接影响调用方能否传递“未设置”信号。传string只能表达“有值”,哪怕值是"";传*string才能表达“未提供”“忽略”“保持原值”等三态语义。
典型场景:数据库更新操作中,只更新用户显式提供的字段。若用户名参数是string,就无法区分“设为空字符串”和“不更新该字段”;换成*string,nil表示跳过,非nil才执行更新。
- ✅ 更新接口参数建议用
*string:func UpdateUser(name *string, email *string) - ✅ 调用时不更新昵称:
UpdateUser(nil, &email) - ✅ 显式设为空昵称:
empty := ""; UpdateUser(&empty, &email) - ❌ 用
string参数无法表达“跳过”意图
strings.TrimSpace("")和len(s) == 0的区别在哪
strings.TrimSpace("")返回"",但strings.TrimSpace(" \t\n")也返回""。单纯用s == ""只能检测原始空字符串,无法识别“全空白字符”。而len(strings.TrimSpace(s)) == 0才是更贴近业务意义的“空”——即用户输入的纯空白内容也视为无效。
注意:strings.TrimSpace会分配新字符串,对高频调用或大字符串有轻微开销;若确定输入不含空白字符,直接s == ""更轻量。
- ✅ 严格判空(含空白):
strings.TrimSpace(s) == "" - ✅ 避免重复分配(已知无空白):
len(s) == 0 - ⚠️ 不要用
len(strings.TrimSpace(s)) == 0——多一次len调用,无必要 - ⚠️
strings.TrimSpace对\uFEFF(BOM)等Unicode空白不生效,需额外处理
string和*string的语义边界——尤其在JSON、DB、API层之间流转时,一个指针层级的差异,就决定了“空”到底是“没给”,还是“给了个空”。


















