🙄
[備忘録]Goで構造体のタグを上書きしてUnmarshalする
※前提として、gopkg.in/yaml.v3
でUnmarshal()
している。
下記の例ではFlowスタイルのYAMLを構造体のfoo
にUnmarshal()
しようとしているが、foo
にタグが無いために失敗している。
main.go
package main
import (
"fmt"
"gopkg.in/yaml.v3"
)
type foo struct {
Value string
}
func main() {
flattenYaml := `{Value: something}`
f := foo{}
if err := yaml.Unmarshal([]byte(flattenYaml), &f); err != nil {
panic(err)
}
fmt.Printf("f: %+v\n", f)
}
実行結果
> go run main.go
f: {Value:}
>
タグの無い構造体にエイリアスを定義したうえで、gopkg.in/yaml.v3
で定義しているインターフェースのobsoleteUnmarshaler
を満たすようメソッドを実装する。
すると、Unmarshal()
実行時にそのメソッドが実行される。
main.go
package main
import (
"fmt"
"gopkg.in/yaml.v3"
)
type foo struct {
Value string
}
// fooのエイリアスを定義
type bar foo
// obsoleteUnmarshaler を満たすメソッドを定義
func (b *bar) UnmarshalYAML(unmarshal func(interface{}) error) error {
// 任意のタグを付与した無名構造体を定義する。
s := &struct {
Value string `yaml:"Value,flow"`
}{}
// barの代わりに上記で定義した無名構造体をUnmarshalに渡す。
if err := unmarshal(s); err != nil {
return err
}
// 成功していれば無名構造体に結果が入っているので、barに渡す。
b.Value = s.Value
return nil
}
func main() {
flattenYaml := `{Value: something}`
f := foo{}
if err := yaml.Unmarshal([]byte(flattenYaml), &f); err != nil {
panic(err)
}
fmt.Printf("f: %+v\n", f)
b := bar{}
if err := yaml.Unmarshal([]byte(flattenYaml), &b); err != nil {
panic(err)
}
fmt.Printf("b: %+v\n", b)
}
実行結果
> go run main.go
f: {Value:}
b: {Value:something}
>
Discussion