给出以下代码:
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,顺便说一句。
答案 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
看到这两个成员A
和B
根本不在Somefin
:
UnmarshalJSON
上看到Wat
,因为来自UnmarshalJSON
的{{1}}被提升为外部Somefin
中的任何匹配元素并提供整个输入答案 1 :(得分:2)
我想出来了。
如果你有这样的结构定义:
type Wat struct {
A, B string
Somefin
}
然后我在OP中描述的错误发生了。但如果你这样做:
type Wat struct {
A, B string
Somefin Somefin
}
然后它没有。查看Chris对此答案的评论,以便对原因进行详细解释。