golangの日記

Go言語を中心にプログラミングについてのブログ

Go言語(golang) 構造体やマップのマージ

golang.png


構造体やマップをマージするためのGo言語のパッケージ mergo の使い方。





目次



構造体のマージ

値が空(ゼロ値)の場合に上書きされる。srcdist 型が異なる場合はエラー src and dst must be of same type になる。

package main

import (
    "fmt"
    "log"

    "github.com/imdario/mergo"
)

type Config struct {
    Name string
    Age  int
}

func main() {
    src := Config{
        Name: "Tanaka",
        Age:  31,
    }

    dist := Config{
        Name: "Suzuki",
    }

    if err := mergo.Merge(&dist, src); err != nil {
        log.Fatal(err)
    }

    // フィールドの値が空の場合のみ上書きされるので Name は上書きされず、Age のみ変更される
    fmt.Printf("%#v\n", dist) // main.Config{Name:"Suzuki", Age:31}
}



オーバーライド

値が空でなくても上書きされる。MergeWithOverwrite 関数も定義してあるけど、内部的には Merge 関数に WithOverride を指定してあるだけ。

package main

import (
    "fmt"
    "log"

    "github.com/imdario/mergo"
)

type Config struct {
    Name string
    Age  int
}

func main() {
    src := Config{
        Name: "Tanaka",
        Age:  31,
    }

    dist := Config{
        Name: "Suzuki",
        Age:  46,
    }

    // 引数に WithOverride を指定する
    if err := mergo.Merge(&dist, src, mergo.WithOverride); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%#v\n", dist) // main.Config{Name:"Tanaka", Age:31}
}



マップのマージ

dist にキーが存在しない場合と、値が空(ゼロ値)の場合に上書きされる。構造体と違って型が異なる場合でも dist の方がゆるい場合(interface{}を使ってるという意味で)はエラーにはならない。逆だとパニックする。

package main

import (
    "fmt"
    "log"

    "github.com/imdario/mergo"
)

func main() {
    src := map[string]interface{}{
        "name": "Tanaka",
        "age":  31,
    }

    dist := map[interface{}]interface{}{
        "name": "",
        "age": 46,
    }

    if err := mergo.Map(&dist, src); err != nil {
        log.Fatal(err)
    }

    // age の値はそのまま
    fmt.Printf("%#v\n", dist) // map[interface {}]interface {}{"age":46, "name":"Tanaka"}
}



オーバーライド

値が空でない場合も src にキー/値があれば上書きされる。構造体のオーバーライドと同じで WithOverride を指定する。MapWithOverwrite 関数も定義してあるけど同じ。

package main

import (
    "fmt"
    "log"

    "github.com/imdario/mergo"
)

func main() {
    src := map[string]interface{}{
        "name": "Tanaka",
        "age":  31,
    }

    dist := map[interface{}]interface{}{
        "age": 46,
    }

    if err := mergo.Map(&dist, src, mergo.WithOverride); err != nil {
        log.Fatal(err)
    }

    // dist の age も上書きされる
    fmt.Printf("%#v\n", dist) // map[interface {}]interface {}{"age":31, "name":"Tanaka"}
}