JSON 和处理未导出的字段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11126793/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:24:47  来源:igfitidea点击:

JSON and dealing with unexported fields

jsongo

提问by user1338952

Is there a technical reason why unexported fields are not included by encoding/json? If not and it is an arbitrary decision could there be an additional back door option (say '+') to include even though unexported?

编码/json 不包含未导出的字段是否存在技术原因?如果不是,并且这是一个任意决定,即使未导出,是否还有其他后门选项(例如“+”)可以包含在内?

Requiring client code to export to get this functionality feels unfortunate, especially if lower case is providing encapsulation or the decision to marshal structures comes much later than design of them.

需要导出客户端代码才能获得此功能感觉很不幸,特别是如果小写字母提供封装或编组结构的决定比设计它们要晚得多。

How are people dealing with this? Just export everything?

人们如何处理这个问题?只是出口一切?

Also, doesn't exporting field names make it difficult to follow suggested idioms. I think if a struct X has field Y, you can not have an accessor method Y(). If you want to provide interface access to Y you have to come up with a new name for the getter and no matter what you'll get something un-idiomatic according to http://golang.org/doc/effective_go.html#Getters

此外,不导出字段名称会使遵循建议的习语变得困难。我认为如果结构 X 具有字段 Y,则您不能拥有访问器方法 Y()。如果你想提供对 Y 的接口访问,你必须为 getter 想出一个新名称,无论你会得到什么,根据http://golang.org/doc/effective_go.html#Getters

回答by Stephen Weinberg

There is a technical reason. The json library does not have the power to view fields using reflect unless they are exported. A package can only view the unexported fields of types within its own package

有技术原因。json 库无权使用反射查看字段,除非它们被导出。一个包只能查看自己包内类型的未导出字段

In order to deal with your problem, what you can do is make an unexported type with exported fields. Json will unmarshal into an unexported type if passed to it without a problem but it would not show up in the API docs. You can then make an exported type that embeds the unexported type. This exported type would then need methods to implement the json.Marshalerand json.Unmarshalerinterfaces.

为了解决您的问题,您可以做的是使用导出字段制作未导出的类型。如果没有问题地传递给 Json,它将解组为未导出的类型,但它不会显示在 API 文档中。然后,您可以创建嵌入未导出类型的导出类型。这个导出的类型需要方法来实现json.Marshalerjson.Unmarshaler接口。

Note: all code is untested and may not even compile.

注意:所有代码都未经测试,甚至可能无法编译。

type jsonData struct {
    Field1 string
    Field2 string
}

type JsonData struct {
    jsonData
}

// Implement json.Unmarshaller
func (d *JsonData) UnmarshalJSON(b []byte) error {
    return json.Unmarshal(b, &d.jsonData)
}

// Getter
func (d *JsonData) Field1() string {
    return d.jsonData.Field1
}

回答by jorelli

Stephen's answer is complete. As an aside, if all you really want is lowercase keys in your json, you can manually specify the key name as follows:

斯蒂芬的回答是完整的。顺便说一句,如果您真正想要的是 json 中的小写键,您可以手动指定键名,如下所示:

type Whatever struct {
    SomeField int `json:"some_field"`
}

In that way, marshaling a Whatever produces the key "some_field" for the field SomeField (instead of having "SomeField" in your json).

通过这种方式,编组一个 What 会为 SomeField 字段生成键“some_field”(而不是在你的 json 中有“SomeField”)。

If you're dead-set on keeping unexported fields, you can also implement the json.Marshaler interface by defining a method with the signature MarshalJSON() ([]byte, error). One way to do this is to use a struct literal that simply has exported versions of the unexported fields, like this:

如果您对保留未导出的字段一无所知,您还可以通过定义一个带有签名的方法来实现 json.Marshaler 接口MarshalJSON() ([]byte, error)。一种方法是使用结构体字面量,它只导出未导出字段的版本,如下所示:

type Whatever struct {
    someField int
}

func (w Whatever) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct{
        SomeField int `json:"some_field"`
    }{
        SomeField: w.someField,
    })
}

That can be a bit cumbersome, so you can also use a map[string]interface{}if you prefer:

这可能有点麻烦,所以map[string]interface{}如果你愿意,你也可以使用:

func (w Whatever) MarshalJSON() ([]byte, error) {
    return json.Marshal(map[string]interface{}{
        "some_field": w.SomeField,
    })
}

However it should be noted that marshaling interface{}has some caveats and can do things like marshal uint64to a float, causing a loss of precision. (all code untested)

但是应该注意的是,编组interface{}有一些注意事项,并且可以执行诸如编组uint64到浮点数之类的事情,从而导致精度损失。(所有代码未经测试)