いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-684 (flag.Visit)(起動時に指定されたフラグを走査, デフォルト値を持つフラグが実際に指定されたかどうか判定)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ · GitHub

概要

以下、自分用のメモです。

flagパッケージに flag.Visit という関数があります。

この関数は Visitor パターンをそのまま表現してくれている関数になります。

なので、引数に指定した関数オブジェクトに順にフラグ値を渡して呼び出してくれます。

この関数ですが、「デフォルト値を持つフラグが実際に指定されたのかどうか」を判定したい場合などに使えたりします。

たまにですが、デフォルト値を持つフラグを「デフォルト値」を意図的に指定して起動された場合に判定して挙動を変えたりしたい場合があったりします。(稀にですが)

後は、設定されたフラグを設定されてないフラグを差分判定したりする場合にも使えます。この場合は map[string]bool とかで指定フラグ名をマッピングしておいたり良くします。

サンプル

main.go

package flags

import (
    "flag"

    "github.com/devlights/gomy/output"
)

// Visit は、flag.Visitのサンプルです。
//
//   - flag.Visit は、「実際にセットされたフラグを順に辞書順で走査してfnを呼ぶ」
//   - flag.VisitAll は、「セット有無に関わらずフラグを順に辞書順で走査してfnを呼ぶ」
//
// という動きになる。デフォルト値を持つフラグで「実際に指定された」かどうかを判定したい場合に使える。
//
// # REFERENCES
//   - https://pkg.go.dev/flag#Visit
func Visit() error {
    type (
        options struct {
            val1          int  // フラグとして使う値(指定される)
            val2          int  // フラグとして使う値(指定されない)
            val1Specified bool // 実際にval1フラグが指定されたかどうか
            val2Specified bool // 実際にval2フラグが指定されたかどうか
        }
    )
    var (
        opts options
        fs   = flag.NewFlagSet("", flag.ExitOnError)
    )
    fs.IntVar(&opts.val1, "v1", -1, "val1")
    fs.IntVar(&opts.val2, "v2", -1, "val2")

    var (
        args = []string{
            "-v1",
            "-1",
        }
    )
    fs.Parse(args)

    //
    // flag.Visit は、当然ながら flag.Parse してから呼び出さないと駄目
    // (parse前に呼び出す事もできるが、何もセットされていないので1回も呼ばれない)
    //
    var (
        fn = func(f *flag.Flag) {
            switch f.Name {
            case "v1":
                opts.val1Specified = true
            case "v2":
                opts.val2Specified = true
            }
        }
    )
    fs.Visit(fn)

    output.Stdoutl("[val1         ]", opts.val1)
    output.Stdoutl("[val1Specified]", opts.val1Specified)
    output.Stdoutl("[val2         ]", opts.val2)
    output.Stdoutl("[val2Specified]", opts.val2Specified)

    return nil
}

実行

入力する値は world という文字列を打ち込んでいるとします。

       $ task
        task: [build] go build -o "/home/dev/dev/github/try-golang/try-golang" .
        task: [run] ./try-golang -onetime

        ENTER EXAMPLE NAME: flags_visit

        [Name] "flags_visit"
        [val1         ]      -1
        [val1Specified]      true
        [val2         ]      -1
        [val2Specified]      false


        [Elapsed] 17.457µs

参考情報

pkg.go.dev

個人的Goのおすすめ書籍

個人的に読んでとても勉強になった書籍さんたちです。


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。