簡単な紹介
では前の記事、私たちは、導入flag
ライブラリを。flag
ライブラリは、コマンドラインオプションを解析するために使用されます。しかし、flag
いくつかの欠点があります。
- 短いオプションのサポートを表示しません。もちろん、記事では、2つのオプションを述べた変数を達成同じ遠回りで共有することができますが、より複雑な書き込みをします。
- より複雑な変数は、各オプションのタイプに応じて呼び出しに対応する、オプションを定義
Type
またはTypeVar
関数。 - デフォルトのサポートのみ限定されたデータタイプ、現在は基本タイプ
bool/int/uint/string
とtime.Duration
、
これらの問題を解決するには、コマンドラインオプションを解析するために、多くのサードパーティのライブラリがあった、今日のヒーローは、go-flags
そのうちの一つです。私が見たのは初めてgo-flags
読んでライブラリをpgwebの時間の源。
go-flags
標準ライブラリが提供するよりもflag
より多くのオプションを。これは、ラベル(構造体タグ)の構造を使用し、反射便利、簡単なインタフェースを提供します。その基本的な機能に加えて、だけでなく、豊富な機能を提供します。
- 短いオプション(-v)と長いオプション(--verbose)をサポートしています。
- サポートなどの短いオプションを、共同書きました
-aux
。 - 複数の値を設定するためのオプションを持ちます。
- これは、すべての基本タイプとマップタイプ、あるいは機能をサポートしています。
- 名前空間とオプショングループをサポートしています。
- などなど。
上記の唯一のラフな説明であるgo-flags
機能、の導入を回してみましょう。
クイックスタート
使用し始めてから学びます!のは、見てみましょうgo-flags
基本的な使用を。
それはサードパーティのライブラリを使用する前にインストールする必要があるので、次のコマンドを実行してインストールします。
$ go get github.com/jessevdk/go-flags
コード内で使用されるimport
ライブラリーに導入します:
import "github.com/jessevdk/go-flags"
完全なサンプルコードは次のとおりです。
package main
import (
"fmt"
"github.com/jessevdk/go-flags"
)
type Option struct {
Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug message"`
}
func main() {
var opt Option
flags.Parse(&opt)
fmt.Println(opt.Verbose)
}
使用するgo-flags
一般的な手順は:
- オプションの構造、オプションタブの設定情報構造を定義します。よる
short
とlong
、設定の短期および長期のオプション名は、description
ヘルプ情報を設定します。コマンドラインパラメータは、短いオプションを追加する前に、とき渡され-
、プラス長い前にオプション--
。 - オプション変数の宣言。
- コール
go-flags
解像度の分析方法を。
(私の環境はWin10 + Gitのバッシュで)コンパイルして、コードを実行します。
$ go build -o main.exe main.go
ショートオプション:
$ ./main.exe -v
[true]
ロングオプション:
$ ./main.exe --verbose
[true]
以降のVerbose
フィールドは、各遭遇スライスタイプである-v
か、--verbose
追加しますtrue
スライスに。
複数の短いオプション:
$ ./main.exe -v -v
[true true]
より長いオプション:
$ ./main.exe --verbose --verbose
[true true]
ショートオプション+長いオプション:
$ ./main.exe -v --verbose -v
[true true true]
短いオプションは、Co-書きました:
$ ./main.exe -vvv
[true true true]
基本的な特性
豊富なデータ型のサポート
go-flags
標準ライブラリと比較するとflag
データ型のより豊富なセットをサポートしています。
- (符号付き整数を含むすべての基本的なタイプ
int/int8/int16/int32/int64
、符号なし整数uint/uint8/uint16/uint32/uint64
、浮動小数点float32/float64
、ブールbool
、文字列string
など)、それらのセクション。 - タイプをマップします。キーのためにのみをサポートする
string
地図の種類の値に基づいて、。 - 関数型。
フィールドタイプスライスベース、ベース型と実質的に解決プロセスに対応するのであれば同じです。違いは、同じオプション遭遇スライスタイプのオプションは、値はスライスに追加されるということです。むしろオプション値のスライスタイプよりも最初に表示され表示される値を上書きします。
次の例を見て:
package main
import (
"fmt"
"github.com/jessevdk/go-flags"
)
type Option struct {
IntFlag int `short:"i" long:"int" description:"int flag value"`
IntSlice []int `long:"intslice" description:"int slice flag value"`
BoolFlag bool `long:"bool" description:"bool flag value"`
BoolSlice []bool `long:"boolslice" description:"bool slice flag value"`
FloatFlag float64 `long:"float", description:"float64 flag value"`
FloatSlice []float64 `long:"floatslice" description:"float64 slice flag value"`
StringFlag string `short:"s" long:"string" description:"string flag value"`
StringSlice []string `long:"strslice" description:"string slice flag value"`
PtrStringSlice []*string `long:"pstrslice" description:"slice of pointer of string flag value"`
Call func(string) `long:"call" description:"callback"`
IntMap map[string]int `long:"intmap" description:"A map from string to int"`
}
func main() {
var opt Option
opt.Call = func (value string) {
fmt.Println("in callback: ", value)
}
err := flags.Parse(&opt, os.Args[1:])
if err != nil {
fmt.Println("Parse error:", err)
return
}
fmt.Printf("int flag: %v\n", opt.IntFlag)
fmt.Printf("int slice flag: %v\n", opt.IntSlice)
fmt.Printf("bool flag: %v\n", opt.BoolFlag)
fmt.Printf("bool slice flag: %v\n", opt.BoolSlice)
fmt.Printf("float flag: %v\n", opt.FloatFlag)
fmt.Printf("float slice flag: %v\n", opt.FloatSlice)
fmt.Printf("string flag: %v\n", opt.StringFlag)
fmt.Printf("string slice flag: %v\n", opt.StringSlice)
fmt.Println("slice of pointer of string flag: ")
for i := 0; i < len(opt.PtrStringSlice); i++ {
fmt.Printf("\t%d: %v\n", i, *opt.PtrStringSlice[i])
}
fmt.Printf("int map: %v\n", opt.IntMap)
}
ベーシックタイプとそのスライスは比較的簡単ですが、あまりにも多くを導入していません。これはすなわち、上記スライスベース型ポインタ、ことは注目に値するPtrStringSlice
フィールドタイプ[]*string
。
構造は、文字列ポインタに格納されているのでgo-flags
、このオプションを解析中に遭遇した文字列を作成し、自動的に、ポインタをセクションに追加されます。
渡して、プログラムを実行します。--pstrslice
オプション:
$ ./main.exe --pstrslice test1 --pstrslice test2
slice of pointer of string flag:
0: test1
1: test2
また、当社は、関数型のオプションを定義することができます。唯一の要件は、String型のパラメータの関数です。それぞれの出会いの解析は、この関数を呼び出すためのオプション値パラメータへのオプションとなります。
上記のコードでは、Call
関数は単に着信オプション値を出力します。渡して、コードを実行します。--call
オプション:
$ ./main.exe --call test1 --call test2
in callback: test1
in callback: test2
最後に、go-flags
また、マップタイプをサポートしていました。キーを制限することでなければならないがstring
タイプ、値がプリミティブ型でなければならないだけでなく、より柔軟な構成を実現します。
map
タイプオプションキー値-によって値:
のようなパーティションはkey:value
、複数設けてもよいです。渡して、コードを実行します。--intmap
オプション:
$ ./main.exe --intmap key1:12 --intmap key2:58
int map: map[key1:12 key2:58]
共通設定
go-flags
設定オプションの多くを提供し、特定の参照ドキュメントを。ここでは、2に焦点を当てるrequired
とdefault
。
required
それは、対応するオプションの値は、それ以外の解析、設定しなければならないことを意味し、空でないErrRequired
エラーを。
default
デフォルト値を設定するオプション。デフォルト値を設定している場合は、required
設定は影響されないかどうか、それは、コマンドライン引数は、このオプションはできませんです。
次の例を参照してください。
package main
import (
"fmt"
"log"
"github.com/jessevdk/go-flags"
)
type Option struct {
Required string `short:"r" long:"required" required:"true"`
Default string `short:"d" long:"default" default:"default"`
}
func main() {
var opt Option
_, err := flags.Parse(&opt)
if err != nil {
log.Fatal("Parse error:", err)
}
fmt.Println("required: ", opt.Required)
fmt.Println("default: ", opt.Default)
}
プログラムを実行し、渡していないdefault
オプション、Default
フィールドのデフォルト値は、合格しないrequired
オプションを、実行エラーを:
$ ./main.exe -r required-data
required: required-data
default: default
$ ./main.exe -d default-data -r required-data
required: required-data
default: default-data
$ ./main.exe
the required flag `/r, /required' was not specified
2020/01/09 18:07:39 Parse error:the required flag `/r, /required' was not specified
先進的な機能
オプションは、グループ化されています
package main
import (
"fmt"
"log"
"os"
"github.com/jessevdk/go-flags"
)
type Option struct {
Basic GroupBasicOption `description:"basic type" group:"basic"`
Slice GroupSliceOption `description:"slice of basic type" group:"slice"`
}
type GroupBasicOption struct {
IntFlag int `short:"i" long:"intflag" description:"int flag"`
BoolFlag bool `short:"b" long:"boolflag" description:"bool flag"`
FloatFlag float64 `short:"f" long:"floatflag" description:"float flag"`
StringFlag string `short:"s" long:"stringflag" description:"string flag"`
}
type GroupSliceOption struct {
IntSlice int `long:"intslice" description:"int slice"`
BoolSlice bool `long:"boolslice" description:"bool slice"`
FloatSlice float64 `long:"floatslice" description:"float slice"`
StringSlice string `long:"stringslice" description:"string slice"`
}
func main() {
var opt Option
p := flags.NewParser(&opt, flags.Default)
_, err := p.ParseArgs(os.Args[1:])
if err != nil {
log.Fatal("Parse error:", err)
}
basicGroup := p.Command.Group.Find("basic")
for _, option := range basicGroup.Options() {
fmt.Printf("name:%s value:%v\n", option.LongNameWithNamespace(), option.Value())
}
sliceGroup := p.Command.Group.Find("slice")
for _, option := range sliceGroup.Options() {
fmt.Printf("name:%s value:%v\n", option.LongNameWithNamespace(), option.Value())
}
}
基本的なコードの我々のスライスタイプと二つの構造を分割するそのタイプのオプション上記のように、このコードは、特に大量のコードの場合には、シャープでより自然に見えるようにすることができます。
これも利点があり、我々は、使用しようとする--help
プログラムを実行します:
$ ./main.exe --help
Usage:
D:\code\golang\src\github.com\darjun\go-daily-lib\go-flags\group\main.exe [OPTIONS]
basic:
/i, /intflag: int flag
/b, /boolflag bool flag
/f, /floatflag: float flag
/s, /stringflag: string flag
slice:
/intslice: int slice
/boolslice bool slice
/floatslice: float slice
/stringslice: string slice
Help Options:
/? Show this help message
/h, /help Show this help message
ヘルプ出力は、パケットが見やすいようにショーの私達のセットに従ったものです。
サブコマンド
go-flags
子供の養育費の受注。我々は、多くの場合、コマンドラインプログラムGitの移動を使用して、サブコマンドの数が多いです。たとえばgo version
、go build
、go run
、git status
、git commit
これらのコマンドは、version/build/run/status/commit
息子のコマンドです。
使用するgo-flags
サブコマンドの定義は簡単です:
package main
import (
"errors"
"fmt"
"log"
"strconv"
"strings"
"github.com/jessevdk/go-flags"
)
type MathCommand struct {
Op string `long:"op" description:"operation to execute"`
Args []string
Result int64
}
func (this *MathCommand) Execute(args []string) error {
if this.Op != "+" && this.Op != "-" && this.Op != "x" && this.Op != "/" {
return errors.New("invalid op")
}
for _, arg := range args {
num, err := strconv.ParseInt(arg, 10, 64)
if err != nil {
return err
}
this.Result += num
}
this.Args = args
return nil
}
type Option struct {
Math MathCommand `command:"math"`
}
func main() {
var opt Option
_, err := flags.Parse(&opt)
if err != nil {
log.Fatal(err)
}
fmt.Printf("The result of %s is %d", strings.Join(opt.Math.Args, opt.Math.Op), opt.Math.Result)
}
サブコマンドを実装する必要がgo-flags
定義されたCommander
インタフェースを:
type Commander interface {
Execute(args []string) error
}
彼らはしていない場合は、コマンドラインの解析-
や--
パラメータが始まり、go-flags
それはサブコマンド名としてそれを解釈しようとします。ラベルの構造使用して、サブコマンドの名前command
指定を。
サブコマンドのパラメータは、パラメータのサブコマンドとして戻ってくる、サブコマンドもオプションを持つことができます。
上記のコードでは、我々は、乗算、除算サブコマンドを減算し、算出した任意の整数の追加を達成することができますmath
。
そして、あなたはどのように使用できるかを見てみましょう:
$ ./main.exe math --op + 1 2 3 4 5
The result of 1+2+3+4+5 is 15
$ ./main.exe math --op - 1 2 3 4 5
The result of 1-2-3-4-5 is -13
$ ./main.exe math --op x 1 2 3 4 5
The result of 1x2x3x4x5 is 120
$ ./main.exe math --op ÷ 120 2 3 4 5
The result of 120÷2÷3÷4÷5 is 1
乗算記号を使用していない、という注意*
と除算記号を/
、彼らは認識できません。
他の
go-flags
ライブラリは、Windowsのフォーマットオプション(のサポートなど、多くの興味深い機能がある/v
と/verbose
)、環境変数からデフォルト値を読み取るiniファイルからデフォルトの設定を読んで、というように。私たちは、自分の研究に行くことができます興味を持っています-
参照
私
私は〜一緒に学び、一緒に進行、GoUpUp []パブリックマイクロチャンネル番号の関心を歓迎します
ブログ記事複数のプラットフォームからこの記事OpenWriteリリース!