
go 的 `json.marshal` 只能序列化导出(首字母大写)的结构体字段,小写开头的字段默认不可见,导致序列化结果为空对象 `{}`。
在 Go 语言中,JSON 序列化依赖于反射机制,而反射仅能访问 已导出(exported)字段——即字段名首字母必须为大写。你提供的代码中,Configitem 和 GuiConfig 的所有字段均以小写字母开头(如 local_address、configs),因此 encoding/json 包在序列化时完全忽略它们,最终输出空 JSON 对象 {}。
✅ 正确做法:将结构体字段改为导出字段(首字母大写),并推荐添加 JSON 标签以控制键名:
type Configitem struct {
LocalAddress string `json:"local_address"`
LocalPort int `json:"local_port"`
Method string `json:"method"`
Password string `json:"password"`
Server string `json:"server"`
ServerPort string `json:"server_port"`
Timeout int `json:"timeout"`
}
type GuiConfig struct {
Configs []*Configitem `json:"configs"`
Index int `json:"index"`
}修改后完整可运行示例:
package main
import (
"encoding/json"
"fmt"
)
type Configitem struct {
LocalAddress string `json:"local_address"`
LocalPort int `json:"local_port"`
Method string `json:"method"`
Password string `json:"password"`
Server string `json:"server"`
ServerPort string `json:"server_port"`
Timeout int `json:"timeout"`
}
type GuiConfig struct {
Configs []*Configitem `json:"configs"`
Index int `json:"index"`
}
func main() {
item1 := &Configitem{
LocalAddress: "eouoeu",
LocalPort: 111,
Method: "eoeoue",
Password: "ouoeu",
Server: "oeuoeu",
ServerPort: "qoeueo",
Timeout: 3333,
}
config1 := &GuiConfig{
Index: 1,
Configs: []*Configitem{item1},
}
data, err := json.Marshal(config1)
if err != nil {
panic(err)
}
fmt.Println(string(data))
// 输出:{"configs":[{"local_address":"eouoeu","local_port":111,"method":"eoeoue","password":"ouoeu","server":"oeuoeu","server_port":"qoeueo","timeout":3333}],"index":1}
}⚠️ 注意事项:
- 即使字段导出,若类型不支持 JSON 编码(如 func、chan、未导出结构体等),仍会报错或跳过;
- 若需保留小写字段名但又不想导出(如封装敏感逻辑),可手动实现 json.Marshaler 接口,自定义序列化逻辑;
- JSON 标签中的 - 表示忽略该字段;omitempty 可在值为空时省略字段(如 json:"name,omitempty");
- 嵌套结构体同样需满足导出规则——子结构体本身类型名也须首字母大写(如 Configitem ✅,configitem ❌)。
总结:Go 的 JSON 序列化严格遵循包可见性规则。“小写 = 私有 = 不可序列化” 是初学者常见陷阱。养成结构体字段首字母大写 + 显式 JSON 标签的习惯,是编写健壮序列化逻辑的基础。










