web-dev-qa-db-ja.com

Golangフラグの再定義

複数のコンポーネントで定義できるフラグがあります。 2つのコンポーネントFooとBarがフラグZedを必要とするが、FooとBarはフラグZedを定義する必要がある場合など、コンポーネントがすでにフラグを定義しているかどうかを知ることはできません。この場合、Goのフラグは、再定義されたエラーフラグでパニックになります。

他の場所で初期化されていない場合にのみ、オプションでフラグを初期化する方法はありますか?または、フラグが既に設定されているかどうかを確認し、フラグの値をルックアップしているかどうかを確認します。

私がこれを行う唯一の方法は、次のようなものです:

var fooFlag *string

func init() {
    if flag.Lookup("foo") == nil {
        fooFlag = flag.String("foo", "", "some flag foo")
    }
}

func initFlags() {
    if fooFlag == nil && flag.Lookup("foo") != nil {
        temp := (*flag.Lookup("foo")).Value.(flag.Getter).Get().(string)
        fooFlag = &temp
    }
}

func main() {
    flag.Parse()
    initFlags()
    ...
}

しかし、これは信じられないほど醜いです(そして、これがどれほどうまくいくかはわかりません)。これについてより良い方法について何か考えはありますか?

7
ElfsЯUs

残念ながら、すべてのフラグは一度しか登録できないため、標準ライブラリを使用する簡単な方法はありません。コードを単純化する方法と、このパターンを回避するために何ができるかを見ていきます。

Flag.FlagSetは役に立たない

_flag.FlagSet_ の使用はソリューションではなく、サブコマンドをサポートするように設計されています(例についてはこの質問を参照してください: GoLangでの独立したフラグセットの定義 )。

それが役に立たない理由を示すために、2つのフラグセットがあると仮定しましょう(1つはflagパッケージの詳細である可能性があります)。最初のフラグセットには_"foo"_および_"bar"_フラグを含めることができ、2番目のフラグセットには_"foo"_および_"baz"_フラグを含めることができます。ユーザーが3つすべての値を指定するとどうなりますか?最初のフラグセットの FlagSet.Parse() への呼び出しはエラーを報告します:

提供されているが定義されていないフラグ:-baz

同様に、2番目のフラグセットのFlagSet.Parse()も、未定義の_-bar_のエラーを報告します。

コードを単純化する

アプローチを維持したい場合は、フラグ変数( flag.StringVar() )を使用してコードを簡略化でき、initFlags()で簡単に取得できますstring値を使用して、次のようにフラグ変数に割り当てます。

_var foo string

func init() {
    if flag.Lookup("foo") == nil {
        flag.StringVar(&foo, "foo", "", "this is foo")
    }
}

func initFlags() {
    // "foo" does exist: if noone else registered it, then we did
    foo = flag.Lookup("foo").Value.(flag.Getter).Get().(string)
}

func main() {
    flag.Parse()
    initFlags()
    ...
}
_

また、このような複数のフラグを処理したい場合は、ヘルパー関数を作成して、(今では「醜い」というコードを)繰り返さないようにする必要があります。

_func regStringVar(p *string, name string, value string, usage string) {
    if flag.Lookup(name) == nil {
        flag.StringVar(p, name, value, usage)
    }
}

func getStringFlag(name string) string {
    return flag.Lookup(name).Value.(flag.Getter).Get().(string)
}
_

上記のヘルパーを使用して、3つのフラグ変数を登録すると、次のようになります。

_var foo, bar, baz string

func init() {
    regStringVar(&foo, "foo", "", "this is foo")
    regStringVar(&bar, "bar", "", "this is bar")
    regStringVar(&baz, "baz", "", "this is baz")
}

func initFlags() {
    foo = getStringFlag("foo")
    bar = getStringFlag("bar")
    baz = getStringFlag("baz")
}

func main() {
    flag.Parse()
    initFlags()
    ...
}
_

解決?

明白な解決策は、異なる名前を使用することです。一般的な名前が衝突する可能性がある場合は、それらにプレフィックスを付けることができます。パッケージ名か何かで。ただし、異なる、異なる、一意の名前を使用する必要があります。

それについて考えてください。同じフラグ(nameと同じ)を使用する場合、なぜ2つの異なる場所で2回登録しようとしているのですか?

複数の場所から同じフラグを使用する場合は、フラグ変数とその登録を「外部委託」します。例えば。これを処理するパッケージを作成し、必要な両方の場所からこのパッケージを参照してください。または、フラグ変数の値を必要な場所に配布してください。

6
icza