解组嵌套 json 字符串使用 json.RawMessage

Unmarshaling nested json string use json.RawMessage

我无法思考如何解组来自先前解组的 json 字节数组的原始 json 字符串。我有当前代码:

type Message struct {
    Event string
    Data json.RawMessage  // how data is parsed depends on the event
}

type CreateMessage struct {
    id int
}

var evt = []byte(`{"event": "create", "data" :{"id":5 }}`)

func main() {
    var message Message
    log.Println(string(evt))
    json.Unmarshal(evt, &message)

    log.Println(message)
    log.Println(message.Event)
    log.Println(string(message.Data))
    fmt.Printf("%+v\n", message)

    var message2 = new(CreateMessage)
    err := json.Unmarshal( message.Data, &message2 )

    log.Println(message2)
    log.Println(err)
}

输出为:

2015/06/29 23:22:10 {"event": "create", "data" :{"id":5 }}
2015/06/29 23:22:10 {create [123 34 105 100 34 58 53 32 125]}
2015/06/29 23:22:10 create
2015/06/29 23:22:10 {"id":5 }
{Event:create Data:[123 34 105 100 34 58 53 32 125]}
2015/06/29 23:22:10 &{0}
2015/06/29 23:22:10 <nil>

为什么我不能将数据解组为 CreateMessage 对象?我尝试了示例 here and here,但他们没有解组嵌套的原始 json 数据,而这正是我想要做的。

问题只是 CreateMessage 结构的 id 字段未导出,它以小写字母开头。将其更改为:

type CreateMessage struct {
    Id int
}

它会起作用。

备注:

因为message2已经是一个指针(new(CreateMessage)),所以不用把它的地址传给json.Unmarshal(),它的值就够了:

var message2 = new(CreateMessage)
if err := json.Unmarshal(message.Data, message2); err != nil {
    panic(err)
}
log.Printf("%+v", message2)

输出:

2009/11/10 23:00:00 &{Id:5}

或者根本不使用 new()

var message2 CreateMessage
if err := json.Unmarshal(message.Data, &message2); err != nil {
    panic(err)
}
log.Printf("%+v", message2)

输出:

2009/11/10 23:00:00 {Id:5}

Go Playground 上试用。

另请注意,现在字段名称为 "Id",JSON 包含 "id",但 json 包 "intelligent" 足以匹配它们(与 "Event""event" 相同)。但是要知道,如果您尝试编组您的结构,输出将包含 "Id" 而不是 "id".

如果您想使用完全不同的字段名称或确保在编组结构时将其小写,您可以使用 struct tags 来说明它在 JSON 文本中的显示方式,例如:

type CreateMessage struct {
    MyId int `json:"id"`
}