string不能直接接收NULL数据库字段,因Go标准库主动拦截以防止语义混淆;必须用*string或sql.NullString等NULL安全类型。
直接用
接收允许为
的数据库字段,一定会 panic —— 这不是配置问题,是 Go
的硬性约束。
为什么
不能直接 Scan
Go 不会把 SQL 的
当作 “空字符串” 或 “零值” 自动转换。它明确拒绝这种语义混淆:
(注意日志里写的是
,实际错误根源是目标字段为非指针
)。
只要数据库列定义为
,且你结构体字段是
、
、
这类值类型,
就会立即失败。
这不是驱动 bug,是标准库的主动拦截,防止业务误把 “缺失” 当 “默认”
字段可放心用值类型,无需额外包装
哪怕你确定某次查询“肯定不 NULL”,只要 schema 允许,就仍需按 NULL 安全方式处理
用
是最简方案,但要注意解引用
Go 标准库原生支持
、
、
等指针类型接收
:遇到
时自动设为
;有值时分配内存并写入。
立即学习
“
go语言免费学习笔记(深入)
”;
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
JSON 序列化也天然友好:
对
输出
,对非 nil 输出字符串字面量。
声明字段为
,
时传
(必须取地址)
使用前必须判空:
,否则 panic
不要在 struct tag 里加
——
不识别,纯属干扰
性能无损耗,没有额外内存分配或 GC 压力
适合需要显式区分“未扫描”和“显式 NULL”
是带
字段的结构体,
表示该字段被扫描过且值为
;
才表示有有效字符串。
它比指针更重一点,但语义更精确 —— 比如你做审计日志,需要明确记录“用户没填昵称”(
)还是“查这条记录时根本没 SELECT 昵称字段”(字段未被扫描,
保持初始
)。
必须用
传给
,否则不会修改字段内容
在
时是空串,直接拼接会出错:
→
JSON 输出需手动控制:
,或封装
整数、布尔、时间分别用
、
、
,别混用
别踩这些坑
很多问题不是逻辑难,是细节漏掉导致运行时崩:
PostgreSQL 的
或 MySQL 的
字段即使允许
,也不能用
扫——得用
或
自定义枚举类型若可能为
,别硬套
,应封装自己的
用
或其他 ORM 时,同样受
约束:值类型字段遇
必报错,必须改指针或
不等于空字符串、零值、false —— 业务上是否要 fallback(比如把
显示为
),必须由你显式决定,没有魔法函数自动兜底
stringNULLdatabase/sqlstringNULLNULLsql: Scan error on column index 0: unsupported Scan, storing driver.Value type into type *string *stringstringNULLstringint64time.TimeScanNOT NULL*string*string*int64*time.TimeNULLNULLniljson.Marshalnil *stringnullUsername *stringScan&u.Usernameif u.Username != nil { use(*u.Username) }sql:"username"database/sqlsql.NullStringsql.NullStringValid boolValid == falseNULLValid == trueNULLValidfalse&u.NameScanu.Name.String!u.Name.Validu.Name.String + " (optional)"" (optional)"if u.Name.Valid { return json.Marshal(u.Name.String) } else { return []byte("null") }MarshalJSONsql.NullInt64sql.NullBoolsql.NullTimeJSONBJSONNULLsql.NullString*stringjson.RawMessageNULLsql.NullStringNullEnumgorpdatabase/sqlNULLsql.NullXXXNULLNULL"-" 