本文详解 go 语言中将 json 数组反序列化为结构体切片的关键要点:字段必须导出(首字母大写)、使用指针传递切片变量、并处理嵌套响应中的实际数据路径。
本文详解 go 语言中将
js
on 数组反序列化为结构体切片的关键要点:字段必须导出(首字母大写)、使用指针传递切片变量、并处理嵌套响应中的实际数据路径。
在 Go 中解析来自外部服务(如 Google Apps Script)的 JSON 响应时,常见错误是结构体字段未导出或解码目标类型不匹配。你提供的原始数据本质上是一个嵌套结构:外层是 map[string]interface{}(含 @type 和 result 键),而真正需要的是 result 字段对应的 JSON 数组部分。
首先,确保你的结构体字段全部
导出
(即首字母大写),否则 encoding/
json
包无法访问和赋值:
注意:我们添加了 json 标签以精确匹配 JSON 键名,并为 prosecution 添加 omitempty,使其在部分对象中缺失时不会报错。
接下来,关键在于
识别并提取 result 字段内容
。原始数据并非纯 JSON 数组,而是形如:
因此不能直接 json.Unmarshal(rawData, &[]Case{}) —— 因为 rawData 是一个 map 的 JSON 表示,不是数组。你需要分两步处理:
先定义一个临时结构体或用 map[string]interface{} 解析外层;
提取 result 字段的字节流([]byte),再二次解码为 []Case。
推荐做法(清晰且类型安全):
Find JSON Path Online
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
下载
✅ 正确调用方式:
⚠️ 常见错误提醒:
❌ json: cannot unmarshal object into Go value of type []Case:说明你传入的是整个对象 JSON(含 @type 和 result),而非 result 内部的数组 JSON;
❌ 字段小写(如 id int)会导致解码静默失败(值保持零值);
❌ 忘记对切片取地址(&cases)将导致解码无效果。
? 进阶建议:若 result 结构稳定,可直接定义完整嵌套结构体;若需高灵活性,结合 json.RawMessage 实现按需解析。始终使用 json.Unmarshal 的错误返回进行校验,避免静默失败。
通过以上步骤,你就能可靠地从 Google Script 的响应中提取结构化案件数据,并在 Go 应用中安全使用。
type Case struct {
ID int `json:"id"`
CaseNumber string `json:"casenumber"`
DateDelivered string `json:"datedelivered"`
Judge string `json:"judge"`
Court string `json:"court"`
Location string `json:"location"`
Accused string `json:"accused"`
Prosecution string `json:"prosecution,omitempty"` // 可选字段,缺失时忽略
Judgment string `json:"judgment"`
}{
"@type": "type.googleapis.com/google.apps.script.v1.ExecutionResponse",
"result": [...]
}type ExecutionResponse struct {
Type string `json:"@type"`
Result json.RawMessage `json:"result"` // 延迟解析 result 字段
}
func parseCases(data []byte) ([]Case, error) {
var resp ExecutionResponse
if err := json.Unmarshal(data, &resp); err != nil {
return nil, fmt.Errorf("failed to unmarshal outer response: %w", err)
}
var cases []Case
if err := json.Unmarshal(resp.Result, &cases); err != nil {
return nil, fmt.Errorf("failed to unmarshal result array: %w", err)
}
return cases, nil
}data := []byte(`{"@type":"...","result":[{"id":1,"casenumber":"Criminal Case 20 of 2012",...}...]}`)
cases, err := parseCases(data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d cases\n", len(cases))