Golang:嵌套的JSON Unmarshaler遇到问题

时间:2013-12-14 19:14:16

标签: json go unmarshalling

给出以下代码:

package main

import (
    "encoding/json"
    "log"
)

type Somefin string

func (s *Somefin) UnmarshalJSON(b []byte) error {
    log.Println("Unmarshaling",string(b))
    *s = Somefin("~"+string(b)+"~")
    return nil
}

type Wat struct {
    A, B string
    *Somefin
}

func main() {
    b := []byte(`{"A":"foo","B":"bar","Somefin":"baz"}`)
    w := &Wat{Somefin: new(Somefin)}

    err := json.Unmarshal(b,w)
    log.Println(w, err)
}

我得到以下输出:

# go run wat.go
2013/12/14 13:59:17 Unmarshaling {"A":"foo","B":"bar","Somefin":"baz"}
2013/12/14 13:59:17 &{  <nil>} <nil>

因此,Somefin密钥由于某种原因试图解组整个结构而不仅仅是它应该的密钥。我这样做错了还是json编码器中的错误?这是1.2,顺便说一句。

2 个答案:

答案 0 :(得分:4)

为什么你最后没有得到结果

这不是解码器中的错误,它是您代码中的错误。你只是分配另一个地址 到s中的本地指针UnmarshalJSON。更正后的代码:

func (s *Somefin) UnmarshalJSON(b []byte) error {
    log.Println("Unmarshaling",string(b))
    sn := Somefin("~"+string(b)+"~")
    *s = sn
    return nil
}

s = &sn的语义:将地址&sn分配给s。这类似于s = 42

*s = sn的语义:将sn的任何内容复制到s所指向的位置。

此要求的一个要求是s指向有效的内存位置,且不能为nil。 代码的使用示例(play):

w := &Wat{Somefin: new(Somefin)}

err := json.Unmarshal(b,w)
log.Printf("%#v (%s)\n", w, err)

关键是使用新的Wat初始化Somefin,以便指针s进入 UnmarshalJSON有效(指向使用new(Somefin)创建的对象)。

为什么要在UnmarshalJSON

中获取整个字符串

嵌入不是多态。而嵌入对象的方法集(在您的情况下 Somefin)被提升到外部,这 not 意味着该方法现在正在运行 嵌入结构而不是嵌入结构。

小例子(play):

type Inner struct { a int }
func (i *Inner) A() int { return i.a }

type Outer struct {
    *Inner
    a int
}

i := &Inner{}
o := Outer{Inner: i}

fmt.Println("Inner.A():", i.A())
fmt.Println("Outer.A():", o.A())

o.a = 2

fmt.Println("Outer.A():", o.A())

使用多态性,您希望Outer.A()返回2,因为方法A()可以在 Outer而不是Inner的范围。嵌入范围永远不会改变 A()将始终在Inner上运行。

同样的效果会阻止UnmarshalJSON看到这两个成员AB 根本不在Somefin

的范围内
  1. JSON库在UnmarshalJSON上看到Wat,因为来自UnmarshalJSON的{​​{1}}被提升为外部
  2. JSON库找不到Somefin中的任何匹配元素并提供整个输入

答案 1 :(得分:2)

我想出来了。

如果你有这样的结构定义:

type Wat struct {
    A, B string
    Somefin
}

然后我在OP中描述的错误发生了。但如果你这样做:

type Wat struct {
    A, B string
    Somefin Somefin
}

然后它没有。查看Chris对此答案的评论,以便对原因进行详细解释。