一尘不染

Golang:嵌套JSON Unmarshaler遇到麻烦

go

给出以下代码:

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。


阅读 611

收藏
2020-07-02

共1个答案

一尘不染

为什么最后没有结果

这不是解码器中的错误,而是代码中的错误。你只是将另一个地址为本地指针sUnmarshalJSON。更正的代码:

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

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

的语义*s = sn:将所有内容复制sn到指向的地方s

这项工作的一项要求是s指向有效的内存位置,并且不能为nil。您的代码用法示例(播放):

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

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

Crucial是Wat使用new进行的初始化,Somefin因此sin
的指针UnmarshalJSON有效(指向使用创建的对象new(Somefin))。

为什么要输入整个字符串 UnmarshalJSON

嵌入不是多态。虽然嵌入对象(在你的情况的方法集 Somefin)提升到外面,但这 并不 意味着该方法现在工作的嵌入结构,而不是嵌入的一个。

小例子(播放):

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库看到UnmarshalJSONWat,因为UnmarshalJSONSomefin被提升到外
  2. JSON库无法在其中找到任何匹配的元素Somefin并提供整个输入
2020-07-02