Go 命令行解析神器入門 - 10 分鐘上手 flag 包

Go 語言內置的 flag 包提供了命令行參數解析的功能。

可以將命令行中的參數輸入轉換爲程序定義的變量值, 使程序具備靈活的用戶交互能力。

本文將介紹 flag 包的使用方法, 主要內容包括

  • flag 包簡介

  • flag 基礎用法

  • flag 參數類型

  • 自定義 flag 解析

  • flag.NewFlagSet

  • flag 其他函數

  • flag 實戰示例

1. flag 包簡介

flag 包實現了命令行參數的解析, 用法簡單, 提供了一系列定義命令行 flag 參數的函數。

由 flag 包解析命令行參數, 可以避免手動解析 os.Args 的繁瑣。

flag 包使得開發命令行工具更加簡單高效。

主要由兩個部分組成:

  • 定義 flags 的變量

  • 調用 flag.Parse() 解析輸入的 flags

2. flag 基礎用法

基本使用方法是先定義命令行參數, 然後調用 flag.Parse() 進行解析。

package main
import (
  "flag"
  "fmt"
)
var flagname = flag.String("flagname", "default", "description")
func main() {
  flag.Parse()
  fmt.Println(*flagname)
}

在 idea 命令行輸入:

go run main.go -flagname value

則會輸出輸入的值 "value"。

可以定義多個 flag, 在解析時會對應解析。

3. flag 參數類型

flag 包支持的命令行參數類型有:

  • flag.String(name, default, usage) // 字符串

  • flag.Int(name, default, usage) // 整數

  • flag.Bool(name, default, usage) // 布爾

  • flag.Float64(name, default, usage) // 浮點數

  • flag.Duration(name, default, usage) // 時間段

例如:

import (
  "flag"
  "fmt"
)
func main() {
  host := flag.String("host", "localhost", "服務器地址")
  port := flag.Int("port", 8080, "服務器端口")
  verbose := flag.Bool("verbose", false, "詳細日誌")
  flag.Parse()
  fmt.Println("服務器地址:", *host)
  fmt.Println("服務器端口:", *port)
  fmt.Println("是否詳細日誌:", *verbose)
}

各種類型的 flag 使用方法類似。

4. 自定義 flag 解析

可以通過實現 flag.Value 接口自定義 flag 解析:

package main
import (
  "flag"
  "fmt"
)
type LogLevel int
const (
  Info LogLevel = iota
  Debug
  Error
)
var logLevel LogLevel
func init() {
  flag.IntVar((*int)(&logLevel), 
  "loglevel", int(Info), 
  "日誌級別 (0: Info, 1: Debug, 2: Error)")
}
func main() {
  flag.Parse()
  fmt.Println("日誌級別:", logLevel)
}

在命令行傳入 myflag 參數時會調用 myFlag 的 Set 方法進行解析。

5. flag.NewFlagSet

FlagSet 可以定義獨立的 flag 組, 方便同時解析多個命令行參數組。

package main
import (
  "flag"
  "fmt"
  "os"
)
var (
  startCmd = flag.NewFlagSet("start", flag.ExitOnError)
  stopCmd  = flag.NewFlagSet("stop", flag.ExitOnError)
)
func main() {
  if len(os.Args) < 2 {
    fmt.Println("缺少子命令")
    os.Exit(1)
  }
  switch os.Args[1] {
  case "start":
    startCmd.Parse(os.Args[2:])
    // 處理start子命令的邏輯
    // 可以在這裏使用startCmd中定義的命令行參數
  case "stop":
    stopCmd.Parse(os.Args[2:])
    // 處理stop子命令的邏輯
    // 可以在這裏使用stopCmd中定義的命令行參數
  default:
    fmt.Println("無效的子命令")
    os.Exit(1)
  }
}

6. flag 其他函數

flag 包還提供了一些其他函數:

  • flag.Args() // 返回非 flag 參數

  • flag.NArg() // 返回非 flag 參數個數

  • flag.NFlag() // 返回使用的 flag 數

可以用於獲取其它命令行參數。

7. flag 實戰示例

下面是一個 web 服務器的例子:

package main
import (
  "flag"
  "fmt"
  "log"
  "net/http"
)
func main() {
  var port int
  var dir string
  flag.IntVar(&port, "port", 80, "server port")
  flag.StringVar(&dir, "dir", ".", "document root dir")
  flag.Parse()
  http.Handle("/", http.FileServer(http.Dir(dir)))
  fmt.Printf("Server started at :%d and serving files from %s\n", port, dir)
  log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}

通過 flag 定義監聽端口和文檔目錄參數, 啓動 Web 服務器。

8. flag 包的優缺點

flag 包的優點是使用簡單方便, 可以很容易地從命令行參數中讀取輸入。

需要注意的是, flag 全部採用全局變量, 多個 flag 之間可以相互影響, 需要注意名稱不要衝突。

另外, 參數的定義是散落在多個包中的, 不便管理。

9. 總結

flag 包提高了命令行程序的靈活性, 使用簡單方便。

flag 包可以輕鬆實現命令行參數的解析

是開發命令行工具時的重要組件之一。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/h_IZBkUe870XTa5zynM3Yg