Тип flag.FlagSet

Тип flag.FlagSet представляет собой набор флагов командной строки, который позволяет создавать изолированные группы флагов. В отличие от глобального flag.CommandLine, каждый экземпляр flag.FlagSet управляет собственными флагами независимо. Это особенно полезно при создании сложных CLI-приложений с подкомандами или при разработке библиотек, которые не должны конфликтовать с основными флагами. Структура flag.FlagSet предоставляет те же методы для определения флагов, что и пакет flag на верхнем уровне, такие как String, Int, Bool и другие.

Создание нового FlagSet

Для создания нового набора флагов используется функция flag.NewFlagSet. Она принимает два параметра: название набора (обычно это имя команды или подкоманды) и режим обработки ошибок типа flag.ErrorHandling. Функция возвращает указатель на новый экземпляр flag.FlagSet, который можно использовать для определения и парсинга флагов.

gopackage main

import (
  "flag"
  "fmt"
)

func main() {
  // Create a new FlagSet named "server"
  fs := flag.NewFlagSet("server", flag.ExitOnError)

  // Define flags within this FlagSet
  host := fs.String("host", "localhost", "Server host")
  port := fs.Int("port", 8080, "Server port")

  // Parse arguments for this FlagSet
  args := []string{"-host", "192.168.1.1", "-port", "9090"}
  fs.Parse(args)

  fmt.Printf("Host: %s, Port: %d\n", *host, *port)
}

Результат выполнения кода:

go"Host: 192.168.1.1, Port: 9090"

Определение флагов в FlagSet

Экземпляр flag.FlagSet предоставляет те же методы для определения флагов, что и глобальный пакет. Все методы возвращают указатель на значение флага, который становится доступным после вызова Parse. В отличие от глобальных флагов, каждый набор хранит свои флаги изолированно, что позволяет использовать одинаковые имена флагов в разных контекстах.

gopackage main

import (
  "flag"
  "fmt"
)

func main() {
  // Create two independent FlagSets
  fs1 := flag.NewFlagSet("cmd1", flag.ExitOnError)
  fs2 := flag.NewFlagSet("cmd2", flag.ExitOnError)

  // Define same flag names in different FlagSets
  verbose1 := fs1.Bool("verbose", false, "Enable verbose mode")
  verbose2 := fs2.Bool("verbose", true, "Enable verbose mode")

  // Parse different arguments for each FlagSet
  fs1.Parse([]string{"-verbose"})
  fs2.Parse([]string{})

  fmt.Printf("fs1 verbose: %v, fs2 verbose: %v\n", *verbose1, *verbose2)
}

Результат выполнения кода:

go"fs1 verbose: true, fs2 verbose: true"

Парсинг аргументов с FlagSet

Метод Parse экземпляра flag.FlagSet выполняет разбор переданного среза строк. В отличие от глобальной функции flag.Parse, которая работает с os.Args, метод Parse принимает срез аргументов явно и не затрагивает глобальное состояние. Это позволяет гибко управлять разбором аргументов для разных команд или подкоманд в одном приложении.

gopackage main

import (
  "flag"
  "fmt"
)

func main() {
  fs := flag.NewFlagSet("app", flag.ExitOnError)
  name := fs.String("name", "default", "User name")
  age := fs.Int("age", 18, "User age")

  // Simulate command-line arguments
  args := []string{"-name", "John", "-age", "30"}
  fs.Parse(args)

  fmt.Printf("Name: %s, Age: %d\n", *name, *age)
}

Результат выполнения кода:

go"Name: John, Age: 30"

Получение информации о флагах

Экземпляр flag.FlagSet предоставляет методы NFlag для получения количества установленных флагов, NArg для получения количества позиционных аргументов, и Arg для доступа к отдельным позиционным аргументам. Метод PrintDefaults выводит справку по всем флагам набора, а Visit и VisitAll позволяют обойти установленные или все определенные флаги соответственно.

gopackage main

import (
  "flag"
  "fmt"
)

func main() {
  fs := flag.NewFlagSet("example", flag.ExitOnError)
  fs.String("config", "config.json", "Path to config file")
  fs.Bool("debug", false, "Enable debug mode")

  args := []string{"-config", "prod.json", "arg1", "arg2"}
  fs.Parse(args)

  fmt.Printf("Number of flags set: %d\n", fs.NFlag())
  fmt.Printf("Number of args: %d\n", fs.NArg())

  if fs.NArg() > 0 {
    fmt.Printf("First arg: %s\n", fs.Arg(0))
  }

  fmt.Println("\nDefaults:")
  fs.PrintDefaults()
}

Результат выполнения кода:

go"Number of flags set: 1"
"Number of args: 2"
"First arg: arg1"

"Defaults:"
"  -config string"
"    Path to config file (default \"config.json\")"
"  -debug"
"    Enable debug mode"

Обработка ошибок в FlagSet

При создании flag.FlagSet можно указать режим обработки ошибок: flag.ExitOnError завершает программу при ошибке, flag.PanicOnError вызывает панику, а flag.ContinueOnError позволяет обработать ошибку программно. Последний режим особенно полезен, когда нужно использовать собственный механизм логирования ошибок или интерактивный ввод.

gopackage main

import (
  "flag"
  "fmt"
)

func main() {
  fs := flag.NewFlagSet("parser", flag.ContinueOnError)
  fs.String("name", "default", "User name")

  // Invalid argument will not cause exit
  args := []string{"-unknown", "value"}
  err := fs.Parse(args)

  if err != nil {
    fmt.Printf("Parse error: %v\n", err)
  }

  // Even with error, we can continue processing
  fmt.Println("Program continues after error")
}

Результат выполнения кода:

go"Parse error: flag provided but not defined: -unknown"
"Program continues after error"

Смотрите также

  • функцию flag.NewFlagSet,
    которая создает новый экземпляр FlagSet
  • структуру flag.CommandLine,
    которая представляет глобальный набор флагов
  • функцию flag.Parse,
    которая парсит глобальный набор флагов
  • функцию flag.VisitAll,
    которая обходит все зарегистрированные флаги