Go 将带有嵌入式接口的结构转换为JSON
我有一个要封送到JSON的结构。它有一个名为Go 将带有嵌入式接口的结构转换为JSON,go,Go,我有一个要封送到JSON的结构。它有一个名为Foo(导出为Foo)的已定义字段和一个data接口字段,我想将一个带有附加JSON字段的动态结构传递给该字段 但是,当数据字段是接口而不是特定结构时,它永远不会导出为JSON。我怎样才能做到这一点 package main import ( "encoding/json" "fmt" ) type data interface{} type foo struct { Foo string `json:"foo,omite
Foo
(导出为Foo
)的已定义字段和一个data
接口字段,我想将一个带有附加JSON字段的动态结构传递给该字段
但是,当数据字段是接口而不是特定结构时,它永远不会导出为JSON。我怎样才能做到这一点
package main
import (
"encoding/json"
"fmt"
)
type data interface{}
type foo struct {
Foo string `json:"foo,omitempty"`
data
}
type bar struct {
Bar string `json:"bar,omitempty"`
}
func main() {
b := bar{"bar"}
f := foo{"foo", b}
byt, err := json.Marshal(f)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(byt))
}
我需要输出如下所示(它需要是平面的,而不是嵌套的):
2种选择:
json.RawMessage
,这样它就不会被自动解码并保留为一个接口您可以通过自定义实现和一点字节切片来实现这一点
func (f foo) MarshalJSON() ([]byte, error) {
type goo foo
g := goo(f)
b1, err := json.Marshal(g)
if err != nil {
return nil, err
}
b2, err := json.Marshal(g.data)
if err != nil {
return nil, err
}
s1 := string(b1[:len(b1)-1])
s2 := string(b2[1:])
return []byte(s1 + ", " + s2), nil
}
请注意,这不是检查字节是否可以被切分,也不考虑代码< >数据< /代码>字段是片断或数组的可能情况,我不确定无论如何您希望它扁平化。
< p>我会编写一个自定义封送器,像这样:func (f foo) MarshalJSON() ([]byte, error) {
type tmp foo
g := tmp(f)
first, err := json.Marshal(g)
if err != nil {
return nil, err
}
second, err := json.Marshal(f.data)
if err != nil {
return nil, err
}
data := make(map[string]interface{})
json.Unmarshal(first, &data)
json.Unmarshal(second, &data)
return json.Marshal(data)
//{"bar":"bar","foo":"foo"}
}
我怀疑你能。最有可能的情况是,您必须对数据本身进行编码并将其插入其余部分。@Volker您能用一个示例代码片段来说明您的想法吗?有两个选项:一个主要问题是,
data
是未报告的类型,这意味着数据
嵌入字段未报告。JSON包不处理未报告的成员。它必须导出才能被封送,尽管这仍然不能解决您的平面json需求(它封送为{“foo”:“foo”,“Data”:{“bar”:“bar”}
),但反射包(json用来封送)的一个轻微的奇怪之处是,可以访问嵌入式未报告结构的导出字段,但嵌入的未报告接口不是。奇怪,但这就是它的工作方式。你能解释一下为什么需要typegoo-foo
,为什么在f
本身上运行相同的代码会导致堆栈溢出吗?typegoo-foo
定义了一个新的类型goo
,它的结构与foo
相同,但只有结构。这意味着foo
的方法在goo
上不可用,包括调用者MarshalJSON
,而字段foo
和data
不可用。因此,json.marshall(g)
将不会调用goo.MarshalJSON
,因为它不存在,从而避免了堆栈溢出。因此,如果不声明新类型,调用json.Marshal(f)
,而foo.MarshalJSON
本身也调用json.Marshal(f)
,将导致无限递归。因此,基本上,类型goo foo
的唯一目的是避免堆栈溢出。谢谢,现在一切都有意义了!
func (f foo) MarshalJSON() ([]byte, error) {
type tmp foo
g := tmp(f)
first, err := json.Marshal(g)
if err != nil {
return nil, err
}
second, err := json.Marshal(f.data)
if err != nil {
return nil, err
}
data := make(map[string]interface{})
json.Unmarshal(first, &data)
json.Unmarshal(second, &data)
return json.Marshal(data)
//{"bar":"bar","foo":"foo"}
}