Go で struct を embed して、inline する

構造体の形をシンプルにし、yaml での Marshaling にも対応させる


Posted on 2020年 2月 24日 (月)
Tags golang, yaml
golang, yaml

Go で struct は embed (埋め込み) できる

1type ReadWriter struct {
2    reader *Reader
3    writer *Writer
4}

go では継承がないため、embed という形で field を引き継がせることができる。 interface の場合は interface のみを embed でき、struct の場合は interface, struct を embed できる。

参考:

さて、go で yaml を扱う際によく利用される gopkg.in の yaml.v2 には struct field tag にて flag を与えることができる。 yaml - GoDoc

この中で inline という flag があり、これを embed した struct と組み合わせると下記のように yaml 出力時に階層を1つ下げて export, import ができる。

 1package main
 2
 3import (
 4    "fmt"
 5    "gopkg.in/yaml.v2"
 6)
 7
 8type A struct {
 9    Foo string `yaml:"foo"`
10    Bar int `yaml:"bar"`
11}
12
13type B struct {
14    EmA A
15}
16
17type C struct {
18    EmA A `yaml:"a,inline"`
19}
20
21func main(){
22    a := A{
23        Foo: "foo",
24        Bar: 1,
25    }
26    b := B{
27        EmA: a,
28    }
29    c := C{
30        EmA: a,
31    }
32
33    aBytes, _ := yaml.Marshal(a)
34    fmt.Printf("%s\n", aBytes)
35
36    bBytes, _ := yaml.Marshal(b)
37    fmt.Printf("%s\n", bBytes)
38
39    cBytes, _ := yaml.Marshal(c)
40    fmt.Printf("%s\n", cBytes)
41}

この実行結果は下記のようになる。

1foo: foo
2bar: 1
3
4ema:
5  foo: foo
6  bar: 1
7
8foo: foo
9bar: 1

この embed して yaml では inline 化するメリットは、例えば Config 構造体のように、いくつかの config を束ねてファイルへ marshal したいケースで、不要な階層を1つ削れる点にある。

 1configA:
 2    foo: foo
 3    bar: 1
 4configB:
 5    baz: baz
 6
 7// これを下記のように marshal できる
 8foo: foo
 9bar: 1
10baz: baz

もちろん、これだと例えば baz field がどの config 構造体に紐づくか分かりづらいという観点もある。 そんなときは、struct field tag に、yaml:"git_api_url" というようなユニーク性を持つ名前を与えることで混乱は避けられる。

Share


See also