Golang:遇到嵌套的JSON Unmarshaler问题 [英] Golang: Having trouble with nested JSON Unmarshaler

查看:153
本文介绍了Golang:遇到嵌套的JSON Unmarshaler问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下代码:

 包主

导入(
编码/ 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)

关键是用 Somefin 初始化 Wat ,以使指针 in
UnmarshalJSON 是有效的(指向使用 new(Somefin)

为什么你要得到整个字符串 UnmarshalJSON



嵌入不是多态。尽管嵌套对象的方法集(在您的情况下为
Somefin )被提升到外部,但这不是 意味着方法现在在嵌入结构上工作
而不是嵌入结构。



小例子( play ):

 类型内部结构{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 范围内:


  1. JSON库在 Wat 上看到 UnmarshalJSON code> UnmarshalJSON 从 Somefin 被提升到外部

  2. JSON库找不到任何匹配 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:

  1. JSON library sees UnmarshalJSON on Wat because UnmarshalJSON from Somefin gets promoted to the outside
  2. JSON library cannot find any matching element in Somefin and delivers the whole input

这篇关于Golang:遇到嵌套的JSON Unmarshaler问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆