自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

命令行參數(shù)的解析:Flag 庫詳解

系統(tǒng)
如果真的遇上了所謂的復(fù)雜場景,那么還可以使用 Golang 的標(biāo)準庫 flag 包來處理命令行參數(shù)。本文將介紹 Golang 標(biāo)準庫中 flag 包的用法。

 [[375481]]

在 Golang 程序中有很多種方法來處理命令行參數(shù)。

簡單的情況下可以不使用任何庫,直接使用 os.Args

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "os" 
  6.  
  7. func main() { 
  8.     if len(os.Args) > 0 { 
  9.         for index, arg := range os.Args { 
  10.             fmt.Printf("args[%d]=%v\n"index, arg) 
  11.         } 
  12.     } 

試著運行一下,第一個參數(shù)是執(zhí)行文件的路徑。

  1. $ go run demo.go hello world hello golang 
  2. args[0]=/var/folders/72/lkr7ltfd27lcf36d75jdyjr40000gp/T/go-build187785213/b001/exe/demo 
  3. args[1]=hello 
  4. args[2]=world 
  5. args[3]=hello 
  6. args[4]=golang 

從上面你可以看到,os.Args 只能處理簡單的參數(shù),而且對于參數(shù)的位置有嚴格的要求。對于一些比較復(fù)雜的場景,就需要你自己定義解析規(guī)則,非常麻煩。

如果真的遇上了所謂的復(fù)雜場景,那么還可以使用 Golang 的標(biāo)準庫 flag 包來處理命令行參數(shù)。

本文將介紹 Golang 標(biāo)準庫中 flag 包的用法。

1. 參數(shù)種類

根據(jù)參數(shù)是否為布爾型,可以分為兩種:

  • 布爾型參數(shù):如 --debug,后面不用再接具體的值,指定就為 True,不指定就為 False非布爾型參數(shù)
  • 非布爾型參數(shù):非布爾型,有可能是int,string 等其他類型,如 --name jack ,后面可以接具體的參數(shù)值

根據(jù)參數(shù)名的長短,還可以分為:

  • 長參數(shù):比如 --name jack 就是一個長參數(shù),參數(shù)名前有兩個 -
  • 短參數(shù):通常為一個或兩個字母(是對應(yīng)長參數(shù)的簡寫),比如 -n ,參數(shù)名前只有一個 -

2. 入門示例

我先用一個字符串類型的參數(shù)的示例,拋磚引玉

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. func main(){ 
  8.     var name string 
  9.     flag.StringVar(&name"name""jack""your name"
  10.  
  11. flag.Parse()  // 解析參數(shù) 
  12.     fmt.Println(name

flag.StringVar 定義了一個字符串參數(shù),它接收幾個參數(shù)

  • 第一個參數(shù) :接收值后,存放在哪個變量里,需為指針
  • 第二個參數(shù) :在命令行中使用的參數(shù)名,比如 --name jack 里的 name
  • 第三個參數(shù) :若命令行中未指定該參數(shù)值,那么默認值為 jack
  • 第四個參數(shù):記錄這個參數(shù)的用途或意義

運行以上程序,輸出如下

  1. $ go run demo.go 
  2. jack 
  3.  
  4. $ go run demo.go --name wangbm 
  5. wangbm 

3. 改進一下

如果你的程序只接收很少的幾個參數(shù)時,上面那樣寫也沒有什么問題。

但一旦參數(shù)數(shù)量多了以后,一大堆參數(shù)解析的代碼堆積在 main 函數(shù)里,影響代碼的可讀性、美觀性。

建議將參數(shù)解析的代碼放入 init 函數(shù)中,init 函數(shù)會先于 main 函數(shù)執(zhí)行。

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. var name string 
  8.  
  9. func init()  { 
  10.     flag.StringVar(&name"name""jack""your name"
  11.  
  12. func main(){ 
  13.     flag.Parse() 
  14.     fmt.Println(name

4. 參數(shù)類型

當(dāng)你在命令行中指定了參數(shù),Go 如何解析這個參數(shù),轉(zhuǎn)化成何種類型,是需要你事先定義的。

不同的參數(shù),對應(yīng)著 flag 中不同的方法。

下面分別講講不同的參數(shù)類型,都該如何定義。

布爾型

實現(xiàn)效果:當(dāng)不指定 --debug 時,debug 的默認值為 false,你一指定 --debug,debug 為賦值為 true。

  1. var debug bool 
  2.  
  3. func init()  { 
  4.     flag.BoolVar(&debug, "debug"false"是否開啟 DEBUG 模式"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(debug) 

運行后,執(zhí)行結(jié)果如下

  1. $ go run main.go  
  2. false 
  3. $ go run main.go --debug 
  4. true 

數(shù)值型

定義一個 age 參數(shù),不指定默認為 18

  1. var age int 
  2.  
  3. func init()  { 
  4.     flag.IntVar(&age, "age", 18, "你的年齡"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(age) 

運行后,執(zhí)行結(jié)果如下

  1. $ go run main.go  
  2. 18 
  3.  
  4. $ go run main.go --age 20 
  5. 20 

int64、 uint 和 float64 類型分別對應(yīng) Int64Var 、 UintVar、Float64Var 方法,也是同理,不再贅述。

字符串

定義一個 name參數(shù),不指定默認為 jack

  1. var name string 
  2.  
  3. func init()  { 
  4.     flag.StringVar(&name"name""jack""你的名字"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(name

運行后,執(zhí)行結(jié)果如下

  1. $ go run main.go  
  2. jack 
  3.  
  4. $ go run main.go --name wangbm 
  5. wangbm 

時間類型

定義一個 interval 參數(shù),不指定默認為 1s

  1. var interval time.Duration 
  2.  
  3. func init()  { 
  4.     flag.DurationVar(&interval, "interval", 1 * time.Second"循環(huán)間隔"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(interval) 

驗證效果如下

  1. $ go run main.go  
  2. 1s 
  3.  
  4. $ go run main.go --interval 2s 
  5. 2s 

5. 自定義類型

flag 包支持的類型有 Bool、Duration、Float64、Int、Int64、String、Uint、Uint64。

這些類型的參數(shù)被封裝到其對應(yīng)的后端類型中,比如 Int 類型的參數(shù)被封裝為 intValue,String 類型的參數(shù)被封裝為 stringValue。

這些后端的類型都實現(xiàn)了 flag.Value 接口,因此可以把一個命令行參數(shù)抽象為一個 Flag 類型的實例。下面是 Value 接口和 Flag 類型的代碼:

  1. type Value interface { 
  2.     String() string 
  3.     Set(string) error 
  4.  
  5. // Flag 類型 
  6. type Flag struct { 
  7.     Name     string // name as it appears on command line 
  8.     Usage    string // help message 
  9.     Value    Value  // value as set 是個 interface,因此可以是不同類型的實例。 
  10.     DefValue string // default value (as text); for usage message 
  11.  
  12. func Var(value Value, name string, usage string) { 
  13.     CommandLine.Var(value, name, usage) 

想要實現(xiàn)自定義類型的參數(shù),其實只要 Var 函數(shù)的第一個參數(shù)對象實現(xiàn) flag.Value接口即可

  1. type sliceValue []string 
  2.  
  3.  
  4. func newSliceValue(vals []string, p *[]string) *sliceValue { 
  5.     *p = vals 
  6.     return (*sliceValue)(p) 
  7.  
  8. func (s *sliceValue) Set(val string) error { 
  9.          // 如何解析參數(shù)值 
  10.     *s = sliceValue(strings.Split(val, ",")) 
  11.     return nil 
  12.  
  13. func (s *sliceValue) String() string { 
  14.     return strings.Join([]string(*s), ","

比如我想實現(xiàn)如下效果,傳入的參數(shù)是一個字符串,以逗號分隔,flag 的解析時將其轉(zhuǎn)成 slice。

  1. $ go run demo.go -members "Jack,Tom" 
  2. [Jack Tom] 

那我可以這樣子編寫代碼

  1. var members []string 
  2. type sliceValue []string 
  3.  
  4.  
  5. func newSliceValue(vals []string, p *[]string) *sliceValue { 
  6.     *p = vals 
  7.     return (*sliceValue)(p) 
  8.  
  9. func (s *sliceValue) Set(val string) error { 
  10.          // 如何解析參數(shù)值 
  11.     *s = sliceValue(strings.Split(val, ",")) 
  12.     return nil 
  13.  
  14.  
  15. func (s *sliceValue) String() string { 
  16.     return strings.Join([]string(*s), ","
  17.  
  18. func init()  { 
  19.     flag.Var(newSliceValue([]string{}, &members), "members""會員列表"
  20.  
  21. func main(){ 
  22.     flag.Parse() 
  23.     fmt.Println(members) 

有的朋友 可能會對 (*sliceValue)(p) 這行代碼有所疑問,這是什么意思呢?

關(guān)于這個,其實之前在 【2.9 詳細圖解:靜態(tài)類型與動態(tài)類型】有講過,忘記了可以前往復(fù)習(xí)。

6. 長短選項

flag 包,在使用上,其實并沒有沒有長短選項之別,你可以看下面這個例子

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. var name string 
  8.  
  9. func init()  { 
  10.     flag.StringVar(&name"name""明哥""你的名字"
  11.  
  12. func main(){ 
  13.     flag.Parse() 
  14.     fmt.Println(name

通過指定如下幾種參數(shù)形式

  1. $ go run main.go  
  2. 明哥 
  3. $ go run main.go --name jack 
  4. jack 
  5. $ go run main.go -name jack 
  6. jack 

一個 - 和兩個 - 執(zhí)行結(jié)果是相同的。

那么再加一個呢?

終于報錯了。說明最多只能指定兩個 -

  1. $ go run main.go ---name jack 
  2. bad flag syntax: ---name 
  3. Usage of /tmp/go-build245956022/b001/exe/main: 
  4.   -name string 
  5.         你的名字 (default "明哥"
  6. exit status 2 

7. 總結(jié)一下

flag 在絕大多數(shù)場景下,它是夠用的,但如果要支持更多的命令傳入格式,flag 可能并不是最好的選擇。

那些在標(biāo)準庫不能解決的場景,往往會有相應(yīng)的Go愛好者提供第三方解決方案。我所了解到的 cobra 就是一個非常不錯的庫。

 本文轉(zhuǎn)載自微信公眾號「Go編程時光」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Go編程時光公眾號。

 

責(zé)任編輯:武曉燕 來源: Go編程時光
相關(guān)推薦

2023-07-05 08:38:48

GolangGo語言

2021-08-10 21:58:54

Go語言Flag庫

2021-11-15 14:30:49

Pythonargparse編程語言

2017-03-08 11:10:39

LinuxShell命令

2021-11-08 10:45:07

Python命令工具

2010-03-10 17:23:37

Python 命令行參

2010-07-15 10:47:22

Perl命令行

2009-12-24 14:51:39

Linux命令行

2010-11-24 15:33:59

mysql命令行參數(shù)

2009-07-20 09:55:30

華為命令行解析華為認證

2010-08-20 10:05:23

用戶命令

2024-05-15 17:05:16

GoLangflagcast

2011-08-22 11:51:13

Linuxconfigure

2010-07-20 14:02:38

Perl命令行參數(shù)

2010-07-26 09:32:41

Perl命令行

2017-05-25 10:32:40

命令linux系統(tǒng)

2010-07-15 11:08:23

Perl命令行

2024-04-29 07:38:20

PythonDocopt開發(fā)

2009-08-11 09:58:22

Linux命令行Linux命令svn命令

2017-06-15 10:32:56

OracleDBV命令行工具
點贊
收藏

51CTO技術(shù)棧公眾號