给出以下代码:
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
key 试图解码整个结构,而不是仅仅解码它应该的 key 。我做错了吗,或者这是json编码器中的错误?顺便说一句,正在进行1.2。 最佳答案
为什么最后没有结果
这不是解码器中的错误,而是代码中的错误。您只是分配另一个地址
到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
)被提升到外部,这并不意味着该方法现在可以正常工作在嵌入式结构而不是嵌入式结构上。
小例子(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
中的Somefin
被提升为外部Somefin
中找到任何匹配的元素,并交付整个输入