Golang:遇到嵌套的JSON Unmarshaler问题 [英] Golang: Having trouble with nested JSON Unmarshaler
问题描述
给出以下代码:
包主
$ p $ >
导入(
编码/ json
log
)
类型Somefin字符串
func(s * Somefin)UnmarshalJSON(b []字节)错误{
log.Println(Unmarshaling,string(b))
* s = Somefin(〜+ string(b)+〜)
return nil
}
类型结构{
A,B字符串
* Somefin
}
func main(){
b:= [ ]字节(`{A:foo,B:bar,Somefin:baz}`)
w:=& Wat {Somefin:new(Somefin)}
err:= json.Unmarshal(b,w)
log.Println(w,err)
}
我得到以下输出: b $ b 2013/12/14 13:59:17 Unmarshaling {A:foo,B:bar,Somefin:baz}
2013/12/14 13: 59:17& {< nil>}< n>
所以 Somefin
键是出于某种原因试图解组整个结构,而不是它应该的关键。我在做这个错误还是这是json编码器中的错误?这是去1.2,顺便说一句。
为什么你在最后没有结果
解码器中没有错误,这是您代码中的一个错误。您只是将另一个地址
分配给 UnmarshalJSON
中的本地指针 s
。更正后的代码:
func(s * Somefin)UnmarshalJSON(b []字节)错误{
log.Println unmarshaling,string(b))
sn:= Somefin(〜+ string(b)+〜)
* s = sn
return nil
}
s =& sn
的语义:将地址& sn
分配给 s
。这类似于 s = 42
。 $ b
* s = sn
:将任何
sn
复制到 s
指向的位置。
这个工作的一个要求是 s
指向一个有效的内存位置,并且不能是 nil
。
代码的示例用法( play ):
w:=& Wat {Somefin:new(Somefin)}
err:= json.Unmarshal(b,w )
log.Printf(%#v(%s)\\\
,w,err)
关键是用 嵌入不是多态。尽管嵌套对象的方法集(在您的情况下为 小例子( play ): 使用多态性,您会期望 同样的效果可以防止 Wat
,以使指针
in
UnmarshalJSON
是有效的(指向使用 new(Somefin)$创建的对象
为什么你要得到整个字符串
UnmarshalJSON
Somefin
)被提升到外部,但这不是 意味着方法现在在嵌入结构上工作
而不是嵌入结构。
类型内部结构{a int}
func(i * Inner)A()int {return ia}
类型外部结构{
* Inner
a int
}
i:=& Inner {}
o:= Outer {Inner:i}
fmt.Println(Inner.A():,iA())$ b $ (Outer.A():,oA())
oa = 2
fmt.Println(Outer.A(): oA())
Outer.A()
返回 2
作为方法 A()
将在
中操作外部
而不是内部
了。嵌入范围永远不会改变,并且
A()
将始终在 Inner
上运行。
UnmarshalJSON
看到两个成员 A
和 B
,因为这些
根本不在 Somefin
范围内:
Wat
上看到 UnmarshalJSON
code> UnmarshalJSON Somefin
被提升到外部
Somefin
中的元素并提供整个输入
Given the following code:
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)
}
I get the following output:
# 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>
So the Somefin
key is for some reason trying to Unmarshal the entire structure instead of just the key it ought to. Am I doing this wrong or is this a bug in the json encoder? This is on go 1.2, btw.
Why you are getting no result at the end
This is no bug in the decoder, it is a bug in your code. You're just assigning another address
to the local pointer s
in UnmarshalJSON
. Corrected code:
func (s *Somefin) UnmarshalJSON(b []byte) error {
log.Println("Unmarshaling",string(b))
sn := Somefin("~"+string(b)+"~")
*s = sn
return nil
}
Semantics of s = &sn
: Assign the address &sn
to s
. This is similar to s = 42
.
Semantics of *s = sn
: Copy whatever is sn
to the place where s
points to.
One requirement for this to work is that s
points to a valid memory location and must not be nil
.
Example usage of your code (play):
w := &Wat{Somefin: new(Somefin)}
err := json.Unmarshal(b,w)
log.Printf("%#v (%s)\n", w, err)
Crucial is the initialization of Wat
with a new Somefin
so that the pointer s
in
UnmarshalJSON
is valid (points to the object created with new(Somefin)
).
Why you are getting the whole string in UnmarshalJSON
Embedding is not polymorphism. While the method set of the embedded object (in your case
Somefin
) is promoted to the outside, this does not mean that the method is now working
on the embedding struct rather than the embedded one.
Small example (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())
With polymorphism you would expect Outer.A()
to return 2
as method A()
would operate in
the scope of Outer
and not Inner
anymore. With embedding the scope is never changed and
A()
will always remain operating on Inner
.
The same effect prevents your UnmarshalJSON
from seeing the two members A
and B
as these
are simply not in the scope of Somefin
:
- JSON library sees
UnmarshalJSON
onWat
becauseUnmarshalJSON
fromSomefin
gets promoted to the outside - JSON library cannot find any matching element in
Somefin
and delivers the whole input
这篇关于Golang:遇到嵌套的JSON Unmarshaler问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!