
本文详解如何使用 Go 的 encoding/json 包将结构体(struct)可靠地序列化为 JSON 字符串,满足 Redis 仅支持字符串存储的约束,并涵盖字段导出规则、结构体标签控制、自定义序列化接口等关键实践。
本文详解如何使用 go 的 `encoding/json` 包将结构体(struct)可靠地序列化为 json 字符串,满足 redis 仅支持字符串存储的约束,并涵盖字段导出规则、结构体标签控制、自定义序列化接口等关键实践。
Redis 本身不支持原生结构体类型,所有数据最终必须以字节数组(即字符串)形式存入。因此,在 Go 中将结构体持久化到 Redis,核心在于高效、可逆、符合约定的序列化与反序列化。encoding/json 是标准库中最常用且生产就绪的方案,它基于反射实现,轻量、稳定且与生态工具链高度兼容。
以下是一个典型工作流示例:
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/go-redis/redis/v9"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
// 注意:Email 字段未导出(小写开头),默认不会被 JSON 编码
email string `json:"-"` // 显式忽略
}
func main() {
// 1. 构造结构体实例
p := Person{Name: "Alice", Age: 30}
// 2. 序列化为 JSON 字符串(用于写入 Redis)
data, err := json.Marshal(p)
if err != nil {
log.Fatal("序列化失败:", err)
}
jsonStr := string(data) // → {"name":"Alice","age":30}
// 3. 模拟写入 Redis(实际中使用 rdb.Set(ctx, "user:1001", jsonStr, 0))
fmt.Println("写入 Redis 的字符串:", jsonStr)
// 4. 从 Redis 读取后反序列化回结构体
var p2 Person
if err := json.Unmarshal([]byte(jsonStr), &p2); err != nil {
log.Fatal("反序列化失败:", err)
}
fmt.Printf("还原后的结构体: %+v\n", p2) // → {Name:"Alice" Age:30 email:""}
}? 关键注意事项:
- 字段必须导出:JSON 编解码依赖反射,只有首字母大写的导出字段(如 Name, Age)才会被处理;小写字段(如 email)默认被忽略,除非显式添加 json:"-" 标签。
-
结构体标签(Struct Tags)是控制核心:
- json:"name":指定 JSON 键名为 name(而非 Name);
- json:"age,omitempty":当 Age == 0 时该字段不输出;
- json:"-":完全排除该字段;
- json:"age,string":将整数以字符串形式编码(如 "age":"30")。
- 避免直接类型转换:string(struct) 在 Go 中非法——结构体不是字节切片,无法强制转换,编译器会报错 cannot convert struct to string。
- 错误处理不可省略:json.Marshal 和 json.Unmarshal 均返回 error,务必检查。忽略错误可能导致静默数据丢失或 panic。
- 性能提示:若高频调用,可考虑预分配 bytes.Buffer 或使用 json.Encoder/Decoder 流式处理;对极致性能场景,亦可评估 msgpack 或 gob(但需确保 Redis 客户端与消费端协议一致)。
✅ 最佳实践总结:
始终为结构体字段添加语义清晰的 JSON 标签;在写入 Redis 前完成序列化并验证结果;读取后立即反序列化并校验字段完整性;对敏感字段(如密码、token)应在序列化前脱敏,而非依赖 json:"-" 隐藏——后者仅防 JSON 层泄露,不替代业务层安全策略。










