我有两个可以转换为JSON的匿名结构体。
a := struct {
Name string `json:"name"`
}{"my name"}
b := struct {
Description string `json:"description"`
}{"my description"}
有没有办法将它们合并成json以获得像这样的东西:
{
"name":"my name",
"description":"my description"
}
你可以在另一个结构体中嵌入这两个结构体。
type name struct {
Name string `json:"name"`
}
type description struct {
Description string `json:"description"`
}
type combined struct {
name
description
}
JSON包将类似于联合体的方式处理嵌入式结构体,但这很快就会变得笨拙。
这有点绕,但我想你可以按照以下方式操作:
a := struct {
Name string `json:"name"`
}{"my name"}
b := struct {
Description string `json:"description"`
}{"my description"}
var m map[string]string
ja, _ := json.Marshal(a)
json.Unmarshal(ja, &m)
jb, _ := json.Marshal(b)
json.Unmarshal(jb, &m)
jm, _ := json.Marshal(m)
fmt.Println(string(jm))
omitempty
的 json 标签,可能会出现问题。如果是这样,空值将不会被擦除。 - Dmytro BoichenkoGo强调组合而非继承。不幸的是,您正在使用匿名结构体,但鉴于您显然正在尝试进行json编组,最好将它们定义为类型:
type name struct {
Name string `json:"name"`
}
type desc struct {
Description string `json:"description"`
}
struct{<fields>}{init}
这样的方式,而是直接写。a := name{"foo"}
b := desc{"Description"}
c := struct {
name
description
}{a, b}
在编写此类类型时,您需要习惯的一个小技巧(可能会让您一开始有些困惑)是如何初始化成员。假设您决定创建一个组合两个其他结构体的类型:
type foo struct {
name
description
}
o := foo{"Name value", "description value"}
Go会抱怨你将类型字符串用作类型name
。你需要编写像这样的代码:
o := foo{
name{"Name value"},
description{Description: "Description val"},//optional with field names
}
c := struct{}{a, b}
)已经实现了这一目的。func (s *MyCompositeType) CopyName(n name) {
s.Name = n.Name
//copy other fields
}
当您嵌套复合类型多层深度时,它可以使生活更加轻松。
{"name": "名称值","description": "描述值"}
。其他类型未导出,嵌入结构体。 - Elias Van Ootegem您可以像这样合并两个结构体:
package main
import (
"fmt"
"encoding/json"
)
type b struct {
Name string `json:"name"`
Description string
Url string
}
type a struct {
*b
MimeType string `json:"mimeType"`
}
func main() {
bc := b{"test", "testdecription", "testurl"}
ac := a{nil, "jpg"}
ac.b = &bc
js, _ := json.Marshal(ac)
fmt.Println(string(js) )
}
其中一种方法是使用内置的reflect
包并通过编程方式创建一个新的结构体!
func stringInSlice(value string, slice []string) bool {
for _, elem := range slice {
if elem == value {
return true
}
}
return false
}
func mergeStructs(structs ...interface{}) reflect.Type {
var structFields []reflect.StructField
var structFieldNames []string
for _, item := range structs {
rt := reflect.TypeOf(item)
for i := 0; i < rt.NumField(); i++ {
field := rt.Field(i)
if !stringInSlice(field.Name, structFieldNames) {
structFields = append(structFields, field)
structFieldNames = append(structFieldNames, field.Name)
}
}
}
return reflect.StructOf(structFields)
}
Go Playground: Link
fmt.Sprintf("{\"name\":%q,\"description\":%q}", a.Name, b.Description)
有什么问题吗?有些事情确实需要一些编程... - Volker