
go结构体转json失败的主因是字段未导出(首字母小写),导致encoding/json包无法通过反射访问,即使赋值成功,json.marshal也返回空对象{},反序列化后字段仍为零值。
go结构体转json失败的主因是字段未导出(首字母小写),导致encoding/json包无法通过反射访问,即使赋值成功,json.marshal也返回空对象{},反序列化后字段仍为零值。
在Go语言中,encoding/json包严格遵循Go的导出规则(Export Rule):只有首字母大写的字段(即导出字段)才能被外部包(包括标准库)通过反射读取或写入。你定义的结构体:
type Message struct {
name string // ❌ 未导出:小写开头 → json包完全不可见
things []string // ❌ 同样未导出
}
尽管fmt.Println(i)能正常打印{Steel [Iron Carbon]}(因为fmt直接访问结构体内存),但json.Marshal(i)实际只看到一个“空壳”——所有字段均不可导出,因此跳过全部字段,最终输出[123 125](即{}的UTF-8字节),反序列化时也无法向name和things写入任何值,结果自然是{ []}。
✅ 正确做法是同时满足两个条件:
- 字段名首字母大写(确保可导出);
- 推荐显式添加json标签(精确控制JSON键名,保持API风格一致)。
修正后的结构体如下:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
type Message struct {
Name string `json:"name"` // ✅ 导出 + 小写JSON键
Things []string `json:"things"` // ✅ 导出 + 小写JSON键
}
完整可运行示例(含错误处理):
package main
import (
"encoding/json"
"fmt"
"log"
)
type Message struct {
Name string `json:"name"`
Things []string `json:"things"`
}
func main() {
i := Message{
Name: "Steel",
Things: []string{"Iron", "Carbon"},
}
fmt.Printf("Go value: %+v\n", i)
// 输出:Go value: {Name:"Steel" Things:[Iron Carbon]}
// ✅ 序列化:检查错误不可省略
b, err := json.Marshal(i)
if err != nil {
log.Fatal("JSON marshaling failed:", err)
}
fmt.Printf("JSON bytes: %v\n", b)
fmt.Printf("JSON string: %s\n", string(b))
// 输出:{"name":"Steel","things":["Iron","Carbon"]}
// ✅ 反序列化:同样需检查错误
var o Message
if err := json.Unmarshal(b, &o); err != nil {
log.Fatal("JSON unmarshaling failed:", err)
}
fmt.Printf("Decoded: %+v\n", o)
// 输出:Decoded: {Name:"Steel" Things:[Iron Carbon]}
}
⚠️ 关键注意事项:
- 导出性优先级高于json标签:即使写了name string \json:"name"``,小写字段依然被忽略;标签仅控制键名映射,不解决可见性问题。
- 类型必须匹配:若JSON中things是字符串数组,Go中必须用[]string;若误用[]int等类型,Unmarshal会静默失败或报错。
- 嵌套结构体同理:若Things是自定义结构体切片,其内部字段也必须导出。
- 生产环境务必检查err:json.Marshal/Unmarshal失败不会panic,但可能返回nil数据或部分解析,忽略错误将导致隐蔽bug。
遵循导出规范 + 显式JSON标签,即可稳定实现Go结构体与标准JSON格式的双向转换,这是构建可靠API、微服务及配置解析系统的基础实践。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










