Go で struct は embed (埋め込み) できる
type ReadWriter struct {
reader *Reader
writer *Writer
}
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 ができる。
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type A struct {
Foo string `yaml:"foo"`
Bar int `yaml:"bar"`
}
type B struct {
EmA A
}
type C struct {
EmA A `yaml:"a,inline"`
}
func main(){
a := A{
Foo: "foo",
Bar: 1,
}
b := B{
EmA: a,
}
c := C{
EmA: a,
}
aBytes, _ := yaml.Marshal(a)
fmt.Printf("%s\n", aBytes)
bBytes, _ := yaml.Marshal(b)
fmt.Printf("%s\n", bBytes)
cBytes, _ := yaml.Marshal(c)
fmt.Printf("%s\n", cBytes)
}
この実行結果は下記のようになる。
foo: foo
bar: 1
ema:
foo: foo
bar: 1
foo: foo
bar: 1
この embed して yaml では inline 化するメリットは、例えば Config 構造体のような、いくつかの config を束ねて、ファイルへ marshal したいというようなケースに不要な階層を1つ削ることができる点がある。
configA:
foo: foo
bar: 1
configB:
baz: baz
// これを下記のように marshal できる
foo: foo
bar: 1
baz: baz
もちろん、これだと例えば baz field がどの config 構造体に紐づくか分かりづらいという観点もある。
そんなときは、struct field tag に、yaml:"git_api_url"
というようなユニーク性を持つ名前を与えることで混乱は避けられる。