【问题标题】:Polymorphic JSON unmarshalling of embedded structs嵌入式结构的多态 JSON 解组
【发布时间】:2017-06-06 01:34:39
【问题描述】:

这是一个例子(另见https://play.golang.org/p/or7z4Xc8tN):

package main

import (
    "encoding/json"
    "fmt"
)

type A struct {
    X string
    Y int
}

type B struct {
    A
    Y string 
}

func main() {
    data := []byte(`{"X": "me", "Y": "hi"}`)
    b := &B{}
    json.Unmarshal(data, b)
    fmt.Println(b)
    fmt.Println(b.A)

    b = &B{}
    data = []byte(`{"X": "me", "Y": 123}`)
    json.Unmarshal(data, b)
    fmt.Println(b)
    fmt.Println(b.A)
}

哪些输出:

&{{me 0} hi}
{me 0}
&{{me 0} }
{me 0}

有没有办法将字段 Y 多态地解组为 int 或字符串?或者甚至因为 B.Y 已定义而完全解组为 A.Y?

我知道有些人可能会建议使用 json.Unmarshall(data, &b.A) 之类的东西来解组,但我不知道我是否可以将它融入我当前的设计中。

【问题讨论】:

标签: json go nested polymorphism unmarshalling


【解决方案1】:

Go 唯一的多态性是接口。嵌入不提供多态性。

如果您尝试在无法假设其中一个字段将是什么类型的情况下解组 JSON,则可以使用类型为 interface{} 的字段以及类型断言、fmt.Sprint 或反射。你应该使用哪个取决于特定的用例——一旦你得到了价值,你将如何处理它?在某些时候,您必须关心它是 int 还是 string,这将决定您如何处理该值。

【讨论】:

    【解决方案2】:

    正如 Adrian 所指出的,Go 不支持通过结构嵌入实现多态性。 interface{} 是保存任何类型的 golang 变量的唯一方法。但是,在您的情况下,您可以实现自定义 Unmarshaler 以使用 json.Numberinterface{} 将 JSON 流解码为结构。下面是使用json.Number 的实现。对于更通用的interface{} 版本,您可以按照 Adrian 的建议实现它。

    func (b *B) UnmarshalJSON(js []byte) error {
        //First: decode stream to anonymous struct
        v := struct {
            X string
            Y json.Number
        }{}
    
        err := json.Unmarshal(js, &v)
        if err != nil {
            return err
        }
    
        //Depends on the v.Y value, choose the holder variable
        //If it's convertible to number, assign to A.Y
        //otherwise, assign it to b.Y
        b.X = v.X
        if fv, err := v.Y.Float64(); err == nil {
            b.A.Y = int(fv)
        } else {
            b.Y = v.Y.String()
        }
    
        return nil
    }
    

    工作示例可以在 The Go Playground 中找到。

    【讨论】:

    • 正如所写,else 永远不会被执行。调用 err := json.Unmarshal(js, &v) 后的返回 err 导致当数据内容不是数字(例如,“hi”)时不会发生 if/else。有了它,else (b.Y = v.Y.String()) 永远不会发生。此外,不会发生 b.X 的分配。在操场示例中,因此输出中缺少“我”。尽管如此,这个例子还是很有帮助的,所以感谢@putu。
    猜你喜欢
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-18
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多