<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 實戰(zhàn) | 讓你的 flag 支持從文件中讀取命令行參數(shù)

          共 3153字,需瀏覽 7分鐘

           ·

          2021-12-09 12:27

          大家好,我是 Go 學堂的漁夫子。今天給大家介紹一個在項目中如何將命令行參數(shù)組織到文件中并進行解析的案例。


          golang標準庫提供了flag包來處理命令行參數(shù)。常規(guī)的使用都是在命令行中啟動服務的時候一一的輸入,讓程序解析。今天給大家介紹一種可以從文件中讀取命令行參數(shù)的實現(xiàn)方法。


          ??01 flag的常規(guī)應用
          下面我們通過代碼來演示下flag的常規(guī)應用。如下代碼:
          var?(
          ??RedisAddress?string
          )

          func?init()?{
          ??flag.StrVar(&RedisAddress,?"redis_address",?"127.0.0.1",?"this?is?redis?address")
          }

          func?main()?{
          ??flag.Parse()
          ??if?RedisAddress?!=?""?{
          ??//redis初始化操作
          ??}
          ??fmt.Printf("redis?address:%s\n",?RedisAddress)
          }

          然后在命令行中進行編譯或直接運行時要指定-redis_address參數(shù),如下:
          go?run?main.go?-redis_address=redisaddr.goxuetang.com

          ?
          隨著項目規(guī)模的增大,需要的命令行參數(shù)越來越多,假設有50個命令行參數(shù)甚至更多,如果我們一個一個指定的話,可想而知會是一件多么可怕的事情:參數(shù)多,難以維護,容易出錯。下面我們就介紹通過讓程序從配置文件中讀取的方法。


          02 通過文件讀取命令行參數(shù)的flag應用
          常規(guī)應用中,我們看到,讀取并解析命令行參數(shù)的邏輯主要在flag.Parse中。我們對flag.Parse()進一步查看,看到源碼包中flag.Parse()函數(shù)實際上是調(diào)用了CommandLine.Parse(arguments []string) error函數(shù),如下:
          func?Parse()?{
          ??//?Ignore?errors;?CommandLine?is?set?for?ExitOnError.
          ??CommandLine.Parse(os.Args[1:])
          }
          通過上面代碼可知,os.Args[1:]就是命令行后跟的所有參數(shù)的集合(在上面的例子中就是 [-redis_address=redisaddr.goxuetang.com]),然后CommandLine.Parse對該字符串集合進行實際的解析。
          那我們要實現(xiàn)的目標實際上就是將文件中的每一行讀取出來,組織成CommandLine.Parse函數(shù)可接收的參數(shù)即可。如下圖所示flag常規(guī)解析和讀取文件方式的示意圖:


          好了,思路講清楚后,我們來看下代碼實現(xiàn)

          03 代碼實現(xiàn)
          我們將實現(xiàn)的函數(shù)封裝在flagx的包中,本文意圖是講解實現(xiàn)的思路,所以在代碼中忽略了錯誤處理,大家在實際項目中自行添加即可。
          package?flagx

          //存儲命令行傳過來的文件路徑
          var?FlagFile?string

          func?init()?{
          ??//注冊命令行的flagfile參數(shù)
          ??flag.Var(&FlagFile,?"flagfile",?"")
          }

          //在Parse函數(shù)中調(diào)用,將解析到的命令行參數(shù)打印出來
          func?visitFlag(f?*flag.Flag)?{
          ??fmt.Println(f.Name?+?"="?+?f.Value.String())
          }

          func?Parse()?error?{
          ??//先解析命令行中的-flagfile參數(shù)
          ??flag.Parse()

          ??var?validFlagLines?[]string

          ??flagContents,?_?:=?ioutil.ReadFile(FlagFile)

          ??configContent?:=?string(flagContents)
          ??//?統(tǒng)一使用\n作為換行符,以便后面按分隔符分隔字符串成切片
          ??configContent?=?strings.Replace(configContent,?"\r\n",?"\n",?-1)
          ??flagLines?:=?strings.Split(configContent,?"\n")
          ??for?_,?line?:=?range?flagLines?{
          ????//忽略掉以?#?開頭的注釋行
          ????if?string([]rune(line)[0])?!=?"#"?{
          ??????//將每一行作為一個有效的命令行參數(shù)
          ??????validFlagLines?=?append(validFlagLines,?line)
          ????}
          ??}

          ??//實際執(zhí)行解析命令行參數(shù)的地方,這里就又和常規(guī)的flag調(diào)用一樣了
          ??_?:=?flag.CommandLine.Parse(validFlagLines)
          ??//將解析到的命令行參數(shù)都按visitFlag函數(shù)的格式輸出
          ??flag.VisitAll(visitFlag)
          ??return?nil
          }

          假設命令行參數(shù)文件存在于文件/data/conf/prod.gflags中,內(nèi)容如下:
          #?redis地址
          -redis_address=redisaddr.goxuetang.com
          #?redis端口
          -redis_port=9999

          #?其他所有的命令行參數(shù)

          好,接下來寫個main函數(shù)測試一下,main函數(shù)中引入的gotech.github.com/m/flagfile/flagx 包是我項目下的定義路徑,大家在實際開發(fā)中根據(jù)自己的項目組織包路徑即可。

          package?main
          import?(
          ??"flag"
          ??"fmt"
          ??"gotech.github.com/m/flagfile/flagx"
          )
          var?(
          ??RedisAddress?string
          ??RedisPort????int
          )

          func?init()?{
          ??flag.StringVar(&RedisAddress,?"redis_address",?"127.0.0.1",?"this?is?redis?address")
          ??flag.IntVar(&RedisPort,?"redis_port",?6379,?"this?is?redis?port")
          }

          func?main()?{
          ??//這里調(diào)用我們自定實現(xiàn)的Parse函數(shù)
          ??err?:=?flagx.Parse()
          ??fmt.Println("err:",?err)

          ??if?RedisAddress?!=?""?&&?RedisPort?!=?0?{
          ??//redis初始化操作
          ??}
          ??fmt.Printf("redis?address:%s,port:%d\n",?RedisAddress,?RedisPort)
          }

          執(zhí)行如下命令
          go?run?main.go?-flagfile=/data/conf/prod.gflags
          04 總結(jié)
          和常規(guī)的flag應用相比,將命令行參數(shù)寫在配置文件中,可以提高命令行參數(shù)的可讀性以及可維護性。該方法的實現(xiàn)思路主要是應用了flag.Parse解析命令行參數(shù)底層的CommandLine.Parse(arguments []string)的函數(shù)功能,將文件中的每行命令行參數(shù)組織成一個切片,然后調(diào)用CommandLine.Parse方法。

          想要了解關(guān)于 Go 的更多資訊,還可以通過掃描的方式,進群一起探討哦~



          瀏覽 64
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  丝袜足交诱惑 | 在线观看中文字幕第一页 | 精品日韩在线 | 欧美成人在线三级免费 | 国产精品无码在线看 |