Golang : pflag 包簡介

筆者在前文中介紹了 Golang 標準庫中 flag 包的用法,事實上有一個第三方的命令行參數解析包 pflag 比 flag 包使用的更爲普遍。pflag 包的設計目的就是替代標準庫中的 flag 包,所以它具備更強大的功能而且與標準的兼容性更好。本文將介紹 pflag 包與 flag 包相比的主要優點,若是你還不瞭解 flag 包的的用法,請參考《Golang : flag 包簡介》一文。本文的演示環境爲 ubuntu 18.04。html

pflag 包的主要特色

pflag 包與 flag 包的工做原理甚至是代碼實現都是相似的,下面是 pflag 相對 flag 的一些優點:git

  • 支持更加精細的參數類型:例如,flag 只支持 uint 和 uint64,而 pflag 額外支持 uint八、uint1六、int32 等類型。
  • 支持更多參數類型:ip、ip mask、ip net、count、以及全部類型的 slice 類型。
  • 兼容標準 flag 庫的 Flag 和 FlagSet:pflag 更像是對 flag 的擴展。
  • 原生支持更豐富的功能:支持 shorthand、deprecated、hidden 等高級功能。

安裝 pflag 包

本文介紹 doker 源代碼中引用的 pflag 包 github.com/spf13/pfla,用下面的命令安裝該包:github

$ go get github.com/spf13/pflag

入門 demo

在 Go workspace 的 src 目錄下建立 pflagdemo 目錄,並在目錄下建立 main.go 文件,編輯其內容以下:golang

package main

import flag "github.com/spf13/pflag"
import (
    "fmt"
    "strings"
)

// 定義命令行參數對應的變量
var cliName = flag.StringP("name", "n", "nick", "Input Your Name")
var cliAge = flag.IntP("age", "a",22, "Input Your Age")
var cliGender = flag.StringP("gender", "g","male", "Input Your Gender")
var cliOK = flag.BoolP("ok", "o", false, "Input Are You OK")
var cliDes = flag.StringP("des-detail", "d", "", "Input Description")
var cliOldFlag = flag.StringP("badflag", "b", "just for test", "Input badflag")

func wordSepNormalizeFunc(f *flag.FlagSet, name string) flag.NormalizedName {
    from := []string{"-", "_"}
    to := "."
    for _, sep := range from {
        name = strings.Replace(name, sep, to, -1)
    }
    return flag.NormalizedName(name)
}

func main() {
    // 設置標準化參數名稱的函數
    flag.CommandLine.SetNormalizeFunc(wordSepNormalizeFunc)
    
    // 爲 age 參數設置 NoOptDefVal
    flag.Lookup("age").NoOptDefVal = "25"

    // 把 badflag 參數標記爲即將廢棄的,請用戶使用 des-detail 參數
    flag.CommandLine.MarkDeprecated("badflag", "please use --des-detail instead")
    // 把 badflag 參數的 shorthand 標記爲即將廢棄的,請用戶使用 des-detail 的 shorthand 參數
    flag.CommandLine.MarkShorthandDeprecated("badflag", "please use -d instead")

    // 在幫助文檔中隱藏參數 gender
    flag.CommandLine.MarkHidden("badflag")

    // 把用戶傳遞的命令行參數解析爲對應變量的值
    flag.Parse()

    fmt.Println("name=", *cliName)
    fmt.Println("age=", *cliAge)
    fmt.Println("gender=", *cliGender)
    fmt.Println("ok=", *cliOK)
    fmt.Println("des=", *cliDes)
}

代碼自己很簡單,也添加了註釋,這裏就再也不過多的解釋了。ubuntu

運行 demo

在 flagdemo 目錄下執行 go build 命令編譯 demo 生成可執行文件 flagdemo。下面咱們經過運行 demo 程序來了解 pflag 包命令行參數的語法特色。函數

布爾類型的參數
布爾類型的參數有下面幾種寫法源碼分析

--flag               // 等同於 --flag=true        
--flag=value
--flag value         // 這種寫法只有在沒有設置默認值時才生效

NoOptDefVal 用法
pflag 包支持經過簡便的方式爲參數設置默認值以外的值,實現方式爲設置參數的 NoOptDefVal 屬性:ui

var cliAge = flag.IntP("age", "a",22, "Input Your Age")
flag.Lookup("age").NoOptDefVal = "25"

下面是傳遞參數的方式和參數最終的取值:spa

Parsed Arguments     Resulting Value
--age=30             cliAge=30
--age                cliAge=25
[nothing]            cliAge=22

shorthand
與 flag 包不一樣,在 pflag 包中,選項名稱前面的 -- 和 - 是不同的。- 表示 shorthand,-- 表示完整的選項名稱。
除了最後一個 shorthand,其它的 shorthand 都必須是布爾類型的參數或者是具備默認值的參數。
因此對於布爾類型的參數和設置了 NoOptDefVal 的參數能夠寫成下面的形式:命令行

-o
-o=true
// 注意,下面的寫法是不正確的
-o true

非布爾類型的參數和沒有設置 NoOptDefVal 的參數的寫法以下:

-g female
-g=female
-gfemale

平常的使用中通常會混合上面的兩類規則:

-aon "jack"
-aon="jack"
-aon"jack"
-aonjack
-oa=35

注意 -- 後面的參數不會被解析:

-oa=35 -- -gfemale

標準化參數的名稱
若是咱們建立了名稱爲 --des-detail 的參數,可是用戶卻在傳參時寫成了 --des_detail 或 --des.detail 會怎麼樣?默認狀況下程序會報錯退出,可是咱們能夠經過 pflag 提供的 SetNormalizeFunc 功能輕鬆的解決這個問題:

func wordSepNormalizeFunc(f *flag.FlagSet, name string) flag.NormalizedName {
    from := []string{"-", "_"}
    to := "."
    for _, sep := range from {
        name = strings.Replace(name, sep, to, -1)
    }
    return flag.NormalizedName(name)
}
flag.CommandLine.SetNormalizeFunc(wordSepNormalizeFunc)

下面的寫法也能正確設置參數了:

--des_detail="person detail"

把參數標記爲即將廢棄
在程序的不斷升級中添加新的參數和廢棄舊的參數都是常見的用例,pflag 包對廢棄參數也提供了很好的支持。經過 MarkDeprecated 和 MarkShorthandDeprecated 方法能夠分別把參數及其 shorthand 標記爲廢棄:

// 把 badflag 參數標記爲即將廢棄的,請用戶使用 des-detail 參數
flag.CommandLine.MarkDeprecated("badflag", "please use --des-detail instead")
// 把 badflag 參數的 shorthand 標記爲即將廢棄的,請用戶使用 des-detail 的 shorthand 參數
flag.CommandLine.MarkShorthandDeprecated("badflag", "please use -d instead")

在幫助文檔中隱藏參數
pflag 包還支持在參數說明中隱藏參數的功能:

// 在幫助文檔中隱藏參數 badflag
flag.CommandLine.MarkHidden("badflag")

看,幫助文檔中沒有顯示 badflag 的信息。其實在把參數標記爲廢棄時,同時也會設置隱藏參數。

總結

正如本文中介紹的,pflag 包提供了不少很是棒的功能,這些功能方便了應用程序的開發者。所以愈來愈多的使用者拋棄標準庫中的 flag 包轉而使用 pflag 包解析命令行參數。

參考:
github spf13/pflag
Golang之使用Flag和Pflag
Golang命令行參數解析庫源碼分析:flag VS pflag

相關文章
相關標籤/搜索