flag 用法參考:
https://golang.google.cn/pkg/flag/
1. 命令源碼文件怎樣接收參數
package main import ( "flag" #導入flag包 "fmt" ) var name string func init(){ flag.StringVar(&name,"name","everyone","The greting object") # } func main(){ flag.Parse() #函數flag.Parse用於真正解析命令參數,並把它們的值賦給相應的變量。 fmt.Printf("hello,%s!\n",name) }
函數flag.StringVar接受 4 個參數。
第 1 個參數是用於存儲該命令參數值的地址,具體到這裏就是在前面聲明的變量name的地址了,由表達式&name表示。
第 2 個參數是爲了指定該命令參數的名稱,這裏是name。
第 3 個參數是爲了指定在未追加該命令參數時的默認值,這裏是everyone。
第 4 個函數參數,即是該命令參數的簡短說明了,這在打印命令說明時會用到。
go run demo2.go -name="huaihe" Hello, huaihe!
2. 怎樣在運行命令源碼文件的時候傳入參數,又怎樣查看參數的使用說明
如果想查看該命令源碼文件的參數說明,可以這樣做:
go run demo2.go --help Usage of /var/folders/4w/lv_wjx0d3b3ff30w0bn_65xc0000gn/T/go-build966482306/b001/exe/demo2: #構建上述命令源碼文件時臨時生成的可執行文件的完整路徑 -name string The greeting object. (default "everyone") exit status 2
如果我們先構建這個命令源碼文件再運行生成的可執行文件,像這樣:
go build demo2.go ls demo2 demo2 ./demo2 --help Usage of ./demo2: -name string The greeting object. (default "everyone") ./demo2 -name="huaihe" Hello, huaihe!
3. 怎樣自定義命令源碼文件的參數使用說明
這有很多種方式,最簡單的一種方式就是對變量flag.Usage重新賦值。flag.Usage的類型是func(),即一種無參數聲明且無結果聲明的函數類型。flag.Usage變量在聲明時就已經被賦值了,所以我們才能夠在運行命令go run demo2.go --help時看到正確的結果。注意,對flag.Usage的賦值必須在調用flag.Parse函數之前。
package main import ( "flag" "fmt" "os" ) var name string func init() { flag.StringVar(&name, "name", "everyone", "The greting object") } func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question") flag.PrintDefaults() } flag.Parse() fmt.Printf("hello,%s!\n", name) }
go run demo2.go --help #這裏並沒有打印臨時文件位置,而是打印了os.Stderr,因爲此時os.Stderr爲空 Usage of question: -name string The greting object (default "everyone") exit status 2
再深入一層,我們在調用flag包中的一些函數(比如StringVar、Parse等等)的時候,實際上是在調用flag.CommandLine變量的對應方法。
flag.CommandLine相當於默認情況下的命令參數容器。所以,通過對flag.CommandLine重新賦值,我們可以更深層次地定製當前命令源碼文件的參數使用說明。
現在我們把main函數體中的那條對flag.Usage變量的賦值語句註銷掉,然後在init函數體的開始處添加如下代碼:
package main import ( "flag" "fmt" "os" ) var name string func init() { flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError) flag.CommandLine.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question") flag.PrintDefaults() } flag.StringVar(&name, "name", "everyone", "The greting object") } func main() { flag.Parse() fmt.Printf("hello,%s!\n", name) }
go run demo2.go --help Usage of question: -name string The greting object (default "everyone") exit status 2
其輸出會與上一次的輸出的一致。不過後面這種定製的方法更加靈活。比如,當我們把爲flag.CommandLine賦值的那條語句改爲:
package main import ( "flag" "fmt" "os" ) var name string func init() { flag.CommandLine = flag.NewFlagSet("", flag.PanicOnError) //注意這裏修改爲flag.PanicOnError flag.CommandLine.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question") flag.PrintDefaults() } flag.StringVar(&name, "name", "everyone", "The greting object") } func main() { flag.Parse() fmt.Printf("hello,%s!\n", name) }
go run demo2.go --help Usage of question: -name string The greting object (default "everyone") panic: flag: help requested goroutine 1 [running]: flag.(*FlagSet).Parse(0xc000096120, 0xc000098010, 0x1, 0x1, 0xc000082f88, 0x100534f) /usr/local/Cellar/go/1.12.7/libexec/src/flag/flag.go:983 +0xf8 flag.Parse(...) /usr/local/Cellar/go/1.12.7/libexec/src/flag/flag.go:998 main.main() /Users/daixuan/pinduoduo/go/src/github.com/Golang_Puzzlers/src/puzzlers/article2/q1/demo2.go:21 +0x78 exit status 2
這是由於我們在這裏傳給flag.NewFlagSet函數的第二個參數值是flag.PanicOnError。flag.PanicOnError和flag.ExitOnError都是預定義在flag包中的常量。
flag.ExitOnError的含義是,告訴命令參數容器,當命令後跟--help或者參數設置的不正確的時候,在打印命令參數使用說明後以狀態碼2結束當前程序。
狀態碼2代表用戶錯誤地使用了命令,而flag.PanicOnError與之的區別是在最後拋出“運行時恐慌(panic)”。
上述兩種情況都會在我們調用flag.Parse函數時被觸發。順便提一句,“運行時恐慌”是 Go 程序錯誤處理方面的概念。關於它的拋出和恢復方法,我在本專欄的後續部分中會講到。
下面再進一步,我們索性不用全局的flag.CommandLine變量,轉而自己創建一個私有的命令參數容器。我們在函數外再添加一個變量聲明:
我們把對flag.StringVar的調用替換爲對cmdLine.StringVar調用,再把flag.Parse()替換爲cmdLine.Parse(os.Args[1:])。其中的os.Args[1:]指的就是我們給定的那些命令參數。這樣做就完全脫離了flag.CommandLine。*flag.FlagSet類型的變量cmdLine擁有很多有意思的方法
package main import ( "flag" "fmt" "os" ) var name string // 方式3。 var cmdLine = flag.NewFlagSet("question", flag.ExitOnError) func init() { // 方式3。 cmdLine.StringVar(&name, "name", "everyone", "The greeting object.") } func main() { // 方式3。 cmdLine.Parse(os.Args[1:]) fmt.Printf("Hello, %s!\n", name) }
go run demo3.go --help Usage of question: -name string The greeting object. (default "everyone") exit status 2 go run demo3.go --name="test" Hello, test!
這樣做的好處依然是更靈活地定製命令參數容器。但更重要的是,你的定製完全不會影響到那個全局變量flag.CommandLine。