web-dev-qa-db-ja.com

Golangで2つの構造体をマージするにはどうすればよいですか?

私は2つのjsonマーシャリング可能な匿名構造体を持っています。

a := struct {
    Name string `json:"name"`
}{"my name"}

b := struct {
    Description string `json:"description"`
}{"my description"}

それらをjsonにマージしてそのようなものを得る方法はありますか?

{
    "name":"my name",
    "description":"my description"
}
9
Dmitry Kapsamun

両方の構造体を別の構造体に埋め込む できます。

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

type description struct {
    Description string `json:"description"`
}

type combined struct {
    name
    description
}

JSONパッケージは、埋め込まれた構造体をユニオンのようなものとして扱いますが、これはかなりすばやく不格好になる可能性があります。

11
nothingmuch

少し複雑ですが、次のようなことができると思います。

    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))
10
Franck Jeannin

次のように2つの構造体をマージできます。

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) )
}
4

囲碁は、継承よりも構成のすべてです。悲しいことに、匿名の構造体を使用していますが、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}

このような型を作成するときに慣れる必要がある1つの癖(最初はつまずくかもしれません)は、メンバーを初期化する方法です。他の2つの構造体を組み合わせるタイプを作成するとします。

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
}

複合タイプを数レベル深くネストすると、作業が楽になります。

3