

現在Goでyamlで書かれた設定ファイルを読み込むロジックを作成しています。

`gopkg.in/yaml.v2`を使ってyamlファイルを読み込むと、`map[interface{}]interface{}`が得られそれを`mitchellh/mapstructure`でそれぞれのapp固有の`config`構造体に変換しています。

コードは以下のようになっています。

**baseapp.go**

[code]

    package common
    
    import (
        "gopkg.in/yaml.v2"
        "io/ioutil"
    )
    
    // BaseApp is base of app.
    type BaseApp struct {
    }
    
    // LoadConfig loads config
    func (ba *BaseApp) LoadConfig(fpath string, config Config) (err error) {
        b, err := ioutil.ReadFile(fpath)
        if err != nil {
            return
        }
        var c interface{}
        if err = yaml.Unmarshal(b, &c); err != nil {
            return
        }
        return config.ConvertMap(c)
    }
    
[/code]

**config.go**

[code]

    package common
    
    type Config interface {
        ConvertMap(input interface{}) error
    }
    
[/code]

これらの使い方は以下のテストのようになっています。

[code]

    package common
    
    import (
        "testing"
    
        "github.com/mitchellh/mapstructure"
    )
    
    type SampleConfig struct {
        Name    string   `yaml:"name"`
        Number  int      `yaml:"number"`
        Strings []string `yaml:"strings"`
    }
    
    //これは共通処理なので構造体ごとに実装したくない。(sc *SampleConfigがかわるだけ)
    func (sc *SampleConfig) ConvertMap(input interface{}) error {
        return mapstructure.Decode(input, &sc)
    }
    
    type SampleApp struct {
        *BaseApp
    }
    
    func TestLoadConfig(t *testing.T) {
        sampleApp := &SampleApp{}
        var sampleConfig SampleConfig
        err := sampleApp.LoadConfig("testdata/sample_config.yml", &sampleConfig)
        if err != nil {
            t.Fatal(err)
        }
    
        if sampleConfig.Name != "test name" {
            t.Errorf("Name is not same as %s: %s", "test name", sampleConfig.Name)
        }
    
        if sampleConfig.Number != 100 {
            t.Errorf("Number is not same as %d: %d", 100, sampleConfig.Number)
        }
    }
    
[/code]

しかしこれでは、それぞれの`config`このテストの例では`SampleConfig`ごとに`ConvertMap`の処理を実装しなければなりません。また`ConvertMap`の実装自体はそれぞれの構造体で同じになってしまいます。

これは無駄なのでどうにかしてそれぞれの`config`で`ConvertMap`を実装する必要をなくしたいのですが、そのようなことは可能でしょうか。


CC BY-SA 3.0
2017-04-21T09:15:05.920
34187
2017-04-21T09:15:05.920
7232
question
go
Goで共通の処理を実装した構造体を埋め込みたい