
本文详解 Go 中解析含嵌套数组的 JSON 时出现 index out of range panic 的根本原因,并提供符合 JSON 规范的结构定义与正确示例。
本文详解 go 中解析含嵌套数组的 json 时出现 `index out of range` panic 的根本原因,并提供符合 json 规范的结构定义与正确示例。
在 Go 中使用 json.Unmarshal 解析 JSON 数据时,结构体字段与 JSON 数据必须严格匹配——不仅字段名(通过 json tag 指定)要一致,数据类型和嵌套结构也必须完全对应。常见错误是误将 JSON 数组元素写成裸值(如字符串),而 Go 结构体中却定义为结构体切片,导致反序列化失败。
例如,原始代码中尝试解析如下非法 JSON:
{ "objects": [ "name": "foo" ] }
该片段语法错误:JSON 数组 [...] 内部不能直接写 "key": "value";它必须由合法的 JSON 值组成——若需表示对象,则每个元素都必须是完整的 JSON 对象,即用花括号 {} 包裹:
✅ 正确格式:
{ "objects": [ {"name": "foo"} ] }
同时,Go 结构体定义本身是正确的:
type jsonobject struct {
Objects []ObjectType `json:"objects"`
}
type ObjectType struct {
Name string `json:"name"`
}
但若输入 JSON 不合法或类型不匹配,json.Unmarshal 不会报错(默认静默失败),而是将 Objects 字段保持为 nil 切片。此时访问 jsontype.Objects[0] 即触发 panic: runtime error: index out of range。
✅ 正确完整示例:
package main
import (
"fmt"
"encoding/json"
)
type JSONObject struct {
Objects []ObjectType `json:"objects"`
}
type ObjectType struct {
Name string `json:"name"`
}
func main() {
// ✅ 正确解析单个对象
bytes1 := []byte(`{"name": "foo"}`)
var obj ObjectType
if err := json.Unmarshal(bytes1, &obj); err != nil {
panic(err)
}
fmt.Printf("Single object: %s\n", obj.Name) // Output: foo
// ✅ 正确解析含数组的对象(注意 JSON 中每个数组元素都是 {} 对象)
bytes2 := []byte(`{"objects": [{"name": "foo"}, {"name": "bar"}]}`)
var jsonObj JSONObject
if err := json.Unmarshal(bytes2, &jsonObj); err != nil {
panic(err)
}
// 安全访问:先检查长度
if len(jsonObj.Objects) > 0 {
fmt.Printf("First object name: %s\n", jsonObj.Objects[0].Name) // Output: foo
} else {
fmt.Println("No objects found")
}
}
? 关键注意事项:
- 永远校验 json.Unmarshal 的返回错误:虽然它可能“成功”返回(如空数组或 nil 字段),但逻辑错误往往源于数据不匹配;
- 访问切片前务必检查长度:避免直接索引 slice[0],应先判断 len(slice) > 0;
- 使用在线工具验证 JSON 格式(如 jsonlint.com),确保数组内元素为合法 JSON 值(对象、字符串、数字等);
- 若需支持多种数组元素类型(如混合字符串与对象),需使用 []interface{} + 类型断言,但推荐优先采用强类型结构体以保障可维护性。
遵循以上原则,即可稳健解析嵌套 JSON 数组,彻底规避 index out of range 运行时 panic。











