Функции пакета flag

Основные функции пакета flag

func Arg

func Arg(i int) string

Arg возвращает i-й аргумент командной строки. Arg(0) — это первый аргумент, оставшийся после обработки флагов. Arg возвращает пустую строку, если запрошенный элемент не существует.

func Args

func Args() []string

Args возвращает аргументы командной строки, не являющиеся флагами.

func Bool

func Bool(name string, value bool, usage string) *bool

Bool определяет флаг bool с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной bool, в которой хранится значение флага.

func BoolFunc

добавлено в go1.21.0

func BoolFunc(name, usage string, fn func(string) error)

BoolFunc определяет флаг с указанным именем и строкой использования без требования значений. Каждый раз, когда флаг встречается, вызывается fn со значением флага. Если fn возвращает ошибку, отличную от nil, она будет рассматриваться как ошибка разбора значения флага.

Пример
package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	// Создаем новый набор флагов
	fs := flag.NewFlagSet("ExampleBoolFunc", flag.ContinueOnError)
	fs.SetOutput(os.Stdout) // Выводим ошибки в stdout

	// Регистрируем BoolFunc флаг
	fs.BoolFunc("log", "logs a dummy message (default: false)", func(s string) error {
		if s == "" {
			// Без значения - просто флаг присутствует
			fmt.Println("dummy message: flag is set")
			return nil
		}

		// С значением - выводим его
		fmt.Printf("dummy message: %s\n", s)
		return nil
	})

	// Пример 1: Флаг без значения
	fmt.Println("\nCase 1: -log (no value)")
	if err := fs.Parse([]string{"-log"}); err != nil {
		fmt.Println("Error:", err)
	}

	// Пример 2: Флаг с произвольным значением
	fmt.Println("\nCase 2: -log=0")
	if err := fs.Parse([]string{"-log=0"}); err != nil {
		fmt.Println("Error:", err)
	}

	// Пример 3: Неизвестный флаг
	fmt.Println("\nCase 3: -unknown")
	if err := fs.Parse([]string{"-unknown"}); err != nil {
		fmt.Println("Error:", err)
	}

	// Пример 4: Вывод помощи
	fmt.Println("\nCase 4: -help")
	fs.PrintDefaults()
}

Запуск программы:

go run main.go -log -log=hello

Результат:

Case 1: -log (no value)
dummy message: flag is set

Case 2: -log=0
dummy message: 0

Case 3: -unknown
Error: flag provided but not defined: -unknown

Case 4: -help
  -log
        logs a dummy message (default: false)

func BoolVar

func BoolVar(p *bool, name string, value bool, usage string)

BoolVar определяет флаг bool с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную bool, в которой будет храниться значение флага.

func Duration

func Duration(name string, value time.Duration, usage string) *time.Duration

Duration определяет флаг time.Duration с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной time.Duration, в которой хранится значение флага. Флаг принимает значение, допустимое для time.ParseDuration.

func DurationVar

func DurationVar(p *time.Duration, name string, value time.Duration, usage string)

DurationVar определяет флаг time.Duration с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную time.Duration, в которой хранится значение флага. Флаг принимает значение, допустимое для time.ParseDuration.

func Float64

func Float64(name string, value float64, usage string) *float64

Float64 определяет флаг float64 с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной float64, в которой хранится значение флага.

func Float64Var

func Float64Var(p *float64, name string, value float64, usage string)

Float64Var определяет флаг float64 с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную float64, в которой хранится значение флага.

func Float64Var

func Float64Var(p *float64, name string, value float64, usage string)

Float64Var определяет флаг float64 с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную float64, в которой будет храниться значение флага.

func Func

func Func(name, usage string, fn func(string) error)

Func определяет флаг с указанным именем и строкой использования. Каждый раз, когда флаг встречается, вызывается функция fn со значением флага. Если fn возвращает ошибку, отличную от nil, это будет расценено как ошибка разбора значения флага.

Пример
package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
)

func main() {
	// Создаем новый набор флагов
	fs := flag.NewFlagSet("ExampleFunc", flag.ContinueOnError)
	fs.SetOutput(os.Stdout)

	// Переменная для хранения IP
	var ip net.IP

	// Регистрируем функцию-парсер для IP
	fs.Func("ip", "`IP address` to parse (e.g. 192.168.1.1 or ::1)", func(s string) error {
		parsedIP := net.ParseIP(s)
		if parsedIP == nil {
			return fmt.Errorf("invalid IP address format: %q", s)
		}
		ip = parsedIP
		return nil
	})

	// Тест 1: Валидный IPv4 адрес
	fmt.Println("Test case 1: Valid IPv4 address")
	if err := fs.Parse([]string{"-ip", "127.0.0.1"}); err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Printf("Parsed IP: %v\n", ip)
		fmt.Printf("Is loopback: %t\n\n", ip.IsLoopback())
	}

	// Тест 2: Невалидный IP адрес
	fmt.Println("Test case 2: Invalid IP address")
	if err := fs.Parse([]string{"-ip", "256.0.0.1"}); err != nil {
		fmt.Printf("Error: %v\n\n", err)
	} else {
		fmt.Printf("Parsed IP: %v\n", ip)
	}

	// Тест 3: Валидный IPv6 адрес
	fmt.Println("Test case 3: Valid IPv6 address")
	if err := fs.Parse([]string{"-ip", "::1"}); err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Printf("Parsed IP: %v\n", ip)
		fmt.Printf("Is loopback: %t\n\n", ip.IsLoopback())
	}

	// Вывод справки
	fmt.Println("Help message:")
	fs.PrintDefaults()
}

Вывод программы:

Test case 1: Valid IPv4 address
Parsed IP: 127.0.0.1
Is loopback: true

Test case 2: Invalid IP address
Error: invalid IP address format: "256.0.0.1"

Test case 3: Valid IPv6 address
Parsed IP: ::1
Is loopback: true

Help message:
  -ip IP address
        `IP address` to parse (e.g. 192.168.1.1 or ::1)

func Int

func Int(name string, value int, usage string) *int

Int определяет флаг int с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной int, в которой хранится значение флага.

func Int64

func Int64(name string, value int64, usage string) *int64

Int64 определяет флаг int64 с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной int64, в которой хранится значение флага.

func Int64Var

func Int64Var(p *int64, name string, value int64, usage string)

Int64Var определяет флаг int64 с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную int64, в которой хранится значение флага.

func IntVar

func IntVar(p *int, name string, value int, usage string)

IntVar определяет флаг int с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную int, в которой будет храниться значение флага.

func NArg

func NArg() int

NArg — количество аргументов, оставшихся после обработки флагов.

func NFlag

func NFlag() int

NFlag возвращает количество установленных флагов командной строки.

func Parse

func Parse()

Parse анализирует флаги командной строки из os.Args[1:]. Должен вызываться после определения всех флагов и до доступа к флагам из программы.

func Parsed

func Parsed() bool

Parsed сообщает, были ли проанализированы флаги командной строки.

func PrintDefaults

func PrintDefaults()

PrintDefaults выводит в стандартный поток ошибок (если не настроено иначе) сообщение об использовании, показывающее настройки по умолчанию всех определенных флагов командной строки. Для флага x с целочисленным значением вывод по умолчанию имеет вид

-x int
    usage-message-for-x (default 7)

Сообщение об использовании будет отображаться в отдельной строке для всех флагов, кроме флагов типа bool с однобайтовым именем.

Для флагов типа bool тип опускается, и если имя флага состоит из одного байта, сообщение об использовании отображается в той же строке.

Значение по умолчанию в скобках опускается, если значение по умолчанию для типа равно нулю.

Указанный тип, в данном случае int, можно изменить, поместив имя в обратные кавычки в строке использования флага; первый такой элемент в сообщении принимается за имя параметра, которое будет отображаться в сообщении, а обратные кавычки удаляются из сообщения при отображении. Например, при задании

flag.String("I", "", "search `directory` for include files")

вывод будет следующим

-I directory
	search directory for include files.

Чтобы изменить место назначения для сообщений флага, вызовите CommandLine.SetOutput.

func Set

func Set(name, value string) error

Set устанавливает значение флага командной строки с указанным именем.

func String

func String(name string, value string, usage string) *string

String определяет строковый флаг с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес строковой переменной, в которой хранится значение флага.

func StringVar

func StringVar(p *string, name string, value string, usage string)

StringVar определяет строковый флаг с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на строковую переменную, в которой хранится значение флага.

func TextVar

func TextVar(p encoding.TextUnmarshaler, name string, value encoding.TextMarshaler, usage string)

TextVar определяет флаг с указанным именем, значением по умолчанию и строкой использования. Аргумент p должен быть указателем на переменную, которая будет хранить значение флага, и p должен реализовывать encoding.TextUnmarshaler. Если флаг используется, его значение будет передано методу UnmarshalText p. Тип значения по умолчанию должен быть таким же, как тип p.

Пример
package main

import (
	"flag"
	"fmt"
	"net"
	"os"
)

func main() {
	// Создаем новый набор флагов
	fs := flag.NewFlagSet("ExampleTextVar", flag.ContinueOnError)
	fs.SetOutput(os.Stdout)

	// Переменная для хранения IP с значением по умолчанию
	var ip net.IP = net.IPv4(192, 168, 0, 100)

	// Регистрируем TextVar флаг для парсинга IP
	fs.TextVar(&ip, "ip", ip, "`IP address` to parse (e.g. 192.168.1.1 or ::1)")

	// Тест 1: Валидный IPv4 адрес
	fmt.Println("Test case 1: Valid IPv4 address (127.0.0.1)")
	if err := fs.Parse([]string{"-ip", "127.0.0.1"}); err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Printf("Parsed IP: %v\n", ip)
		fmt.Printf("Is loopback: %t\n\n", ip.IsLoopback())
	}

	// Тест 2: Невалидный IP адрес
	fmt.Println("Test case 2: Invalid IP address (256.0.0.1)")
	ip = nil // Сбрасываем предыдущее значение
	if err := fs.Parse([]string{"-ip", "256.0.0.1"}); err != nil {
		fmt.Printf("Error: %v\n\n", err)
	} else {
		fmt.Printf("Parsed IP: %v\n\n", ip)
	}

	// Тест 3: Вывод справки
	fmt.Println("Test case 3: Help message")
	fs.PrintDefaults()
}

Вывод программы:

Test case 1: Valid IPv4 address (127.0.0.1)
Parsed IP: 127.0.0.1
Is loopback: true

Test case 2: Invalid IP address (256.0.0.1)
Error: invalid IP address: 256.0.0.1

Test case 3: Help message
  -ip IP address
        `IP address` to parse (e.g. 192.168.1.1 or ::1) (default 192.168.0.100)

func Uint

func Uint(name string, value uint, usage string) *uint

Uint определяет флаг uint с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной uint, которая хранит значение флага.

func Uint64

func Uint64(name string, value uint64, usage string) *uint64

Uint64 определяет флаг uint64 с указанным именем, значением по умолчанию и строкой использования. Возвращаемое значение — адрес переменной uint64, в которой хранится значение флага.

func Uint64Var

func Uint64Var(p *uint64, name string, value uint64, usage string)

Uint64Var определяет флаг uint64 с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную uint64, в которой будет храниться значение флага.

func UintVar

func UintVar(p *uint, name string, value uint, usage string)

UintVar определяет флаг uint с указанным именем, значением по умолчанию и строкой использования. Аргумент p указывает на переменную uint, в которой будет храниться значение флага.

func UnquoteUsage

func UnquoteUsage(flag *Flag) (name string, usage string)

UnquoteUsage извлекает имя в обратных кавычках из строки использования для флага и возвращает его и использование без кавычек. При заданном “a `name` to show” возвращает (“name”, “a name to show”). Если обратные кавычки отсутствуют, имя является обоснованным предположением о типе значения флага или пустой строкой, если флаг является булевым.

func Var

func Var(value Value, name string, usage string)

Var определяет флаг с указанным именем и строкой использования. Тип и значение флага представлены первым аргументом типа Value, который обычно содержит пользовательскую реализацию Value. Например, вызывающий может создать флаг, который преобразует строку, разделенную запятыми, в набор строк, предоставив набору методы Value; в частности, Set разложит строку, разделенную запятыми, на набор.

Пример

Пример использования flag.Var() с пользовательским типом

package main

import (
	"errors"
	"flag"
	"fmt"
	"strings"
)

// StringSet - пользовательский тип для множества строк
type StringSet map[string]struct{}

// String реализует интерфейс flag.Value
func (s StringSet) String() string {
	return strings.Join(s.ToSlice(), ",")
}

// Set реализует интерфейс flag.Value
func (s StringSet) Set(value string) error {
	if len(s) > 0 {
		return errors.New("StringSet already set")
	}
	
	for _, item := range strings.Split(value, ",") {
		item = strings.TrimSpace(item)
		if item != "" {
			s[item] = struct{}{}
		}
	}
	return nil
}

// ToSlice преобразует StringSet в срез строк
func (s StringSet) ToSlice() []string {
	result := make([]string, 0, len(s))
	for k := range s {
		result = append(result, k)
	}
	return result
}

func main() {
	// Инициализируем наш StringSet
	var tags StringSet = make(map[string]struct{})

	// Регистрируем флаг через flag.Var
	flag.Var(&tags, "tags", "comma-separated list of tags")

	// Парсим аргументы командной строки
	flag.Parse()

	// Выводим результат
	fmt.Println("Tags count:", len(tags))
	fmt.Println("Tags list:", tags.ToSlice())

	// Примеры запуска:
	//   go run main.go -tags=go,programming,example
	//   go run main.go -tags="rust, systems programming"
}

Ключевые компоненты:

  1. Пользовательский тип StringSet:

    • Реализует интерфейс flag.Value с методами String() и Set()
    • Хранит уникальные строки как ключи map
  2. Метод Set():

    • Разбивает строку по запятым
    • Игнорирует пустые элементы
    • Возвращает ошибку при повторной установке
  3. Метод String():

    • Формирует строку из элементов через запятую
    • Используется для вывода значения по умолчанию
  4. Дополнительный метод ToSlice():

    • Удобное преобразование в срез строк

Как это работает:

  1. При вызове flag.Var() пакет flag получает:

    • Указатель на наш StringSet
    • Имя флага (“tags”)
    • Описание для справки
  2. При парсинге аргументов:

    • Для флага -tags=go,programming вызывается Set("go,programming")
    • Наш метод разбивает строку и заполняет map
  3. При выводе справки:

    • Вызывается String() для показа текущего значения

func Visit

func Visit(fn func(*Flag))

Visit посещает флаги командной строки в лексикографическом порядке, вызывая fn для каждого из них. Он посещает только те флаги, которые были установлены.

func VisitAll

func VisitAll(fn func(*Flag))

VisitAll посещает флаги командной строки в лексикографическом порядке, вызывая fn для каждого из них. Он посещает все флаги, даже те, которые не были установлены.