使用自定义MarshalJSON()方法嵌入结构的惯用方式 [英] Idiomatic way to embed struct with custom MarshalJSON() method

查看:168
本文介绍了使用自定义MarshalJSON()方法嵌入结构的惯用方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下结构:

type Person {
    Name string `json:"name"`
}

type Employee {
    Person
    JobRole string `json:"jobRole"`
}

我可以轻松地按预期将雇员编组为JSON:

I can easily marshal an Employee to JSON as expected:

p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))

输出:


{ name: Bob, jobRole: Sales}

{"name":"Bob","jobRole":"Sales"}

但是当嵌入式结构具有自定义的 MarshalJSON()方法...

But when the embedded struct has a custom MarshalJSON() method...

func (p *Person) MarshalJSON() ([]byte,error) {
    return json.Marshal(struct{
        Name string `json:"name"`
    }{
        Name: strings.ToUpper(p.Name),
    })
}

它完全崩溃:

p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))

现在结果为:


{ name: BOB}

{"name":"BOB"}

(请注意,明显缺少 jobRole 字段)

(Note the conspicuous lack of jobRole field)

这很容易预料到……嵌入的 Person struct实现了 MarshalJSON()函数,该函数被调用。

This is easily anticipated... the embedded Person struct implements the MarshalJSON() function, which is being called.

麻烦的是,这不是什么我想要。我想要的是:

The trouble is, it's not what I want. What I want would be:


{ name: BOB, jobRole: Sales}

{"name":"BOB","jobRole":"Sales"}

也就是说,通常对 Employee 的字段进行编码,并推迟到 Person MarshalJSON()方法来整理其字段,并交出一些整洁的JSON。

That is, encode Employee's fields normally, and defer to Person's MarshalJSON() method to marshal its fields, and hand back some tidy JSON.

现在我也可以向 Employee 添加 MarshalJSON()方法,但这需要我知道嵌入类型也实现了 MarshalJSON(),并且(a)复制其逻辑,或(b)调用 Person MarshalJSON()并以某种方式操纵其输出以适合我的需要。哪一种方法似乎都是草率的,而且还不是很有前途的(如果我某天无法控制的嵌入式类型会添加自定义的 MarshalJSON()方法怎么办?)

Now I could add a MarshalJSON() method to Employee as well, but this requires that I know that the embedded type implements MarshalJSON() as well, and either (a) duplicate its logic, or (b) call Person's MarshalJSON() and somehow manipulate its output to fit where I want it. Either approach seems sloppy, and not very future proof (what if an embedded type I don't control some day adds a custom MarshalJSON() method?)

这里有我没有考虑过的替代方案吗?

Are there any alternatives here that I haven't considered?

推荐答案

不要将 MarshalJSON 放在 Person 上,因为这已被提升为外部类型。而是使用类型名称字符串并使用 Name 实现 MarshalJSON 。然后将 Person 更改为

Don't put MarshalJSON on Person since that's being promoted to the outer type. Instead make a type Name string and have Name implement MarshalJSON. Then change Person to

type Person struct {
    Name Name `json:"name"`
}

示例: https://play.golang.org/p/u96T4C6PaY

更新

要更一般地解决此问题,您将必须实现 MarshalJSON 放在外部类型上。内部类型的方法被提升为外部类型,因此您不会去解决这个问题。您可以让外部类型调用内部类型的 MarshalJSON ,然后将其解组为通用结构,例如 map [string] interface {} 并添加您自己的字段。这个示例可以做到,但是它具有更改最终输出字段顺序的副作用

To solve this more generically you're going to have to implement MarshalJSON on the outer type. Methods on the inner type are promoted to the outer type so you're not going to get around that. You could have the outer type call the inner type's MarshalJSON then unmarshal that into a generic structure like map[string]interface{} and add your own fields. This example does that but it has a side effect of changing the order of the final output fields

https://play.golang.org/p/ut3e21oRdj

这篇关于使用自定义MarshalJSON()方法嵌入结构的惯用方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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