Функция flag.Var

Функция flag.Var позволяет связать пользовательский тип данных с флагом командной строки. Первым параметром она принимает значение, реализующее интерфейс flag.Value, вторым - имя флага в виде строки, третьим - значение по умолчанию в виде строки, четвертым - описание флага. Функция используется когда стандартные типы флагов не подходят для решения задачи.

Синтаксис

goflag.Var(value flag.Value, name string, defaultValue string, usage string)

Интерфейс flag.Value

Для работы с flag.Var необходимо реализовать интерфейс flag.Value, который содержит два метода:

gotype Value interface {
  String() string
  Set(string) error
}

Метод String возвращает строковое представление значения флага, а метод Set устанавливает новое значение из строки и возвращает ошибку в случае некорректных данных.

Пример

Давайте создадим флаг для работы с цветами в формате RGB:

gopackage main

import (
  "flag"
  "fmt"
  "strconv"
  "strings"
)

type Color struct {
  R, G, B int
}

func (c *Color) String() string {
  return fmt.Sprintf("RGB(%d,%d,%d)", c.R, c.G, c.B)
}

func (c *Color) Set(value string) error {
  parts := strings.Split(value, ",")
  if len(parts) != 3 {
    return fmt.Errorf("invalid color format, expected R,G,B")
  }

  r, err := strconv.Atoi(parts[0])
  if err != nil {
    return err
  }
  g, err := strconv.Atoi(parts[1])
  if err != nil {
    return err
  }
  b, err := strconv.Atoi(parts[2])
  if err != nil {
    return err
  }

  c.R, c.G, c.B = r, g, b
  return nil
}

func main() {
  var color Color
  flag.Var(&color, "color", "255,0,0", "RGB color values separated by commas")
  flag.Parse()

  fmt.Printf("Selected color: %s\n", color.String())
}

Запустим программу с различными параметрами:

go$ go run main.go -color 255,0,0
"Selected color: RGB(255,0,0)"

$ go run main.go -color 0,255,0
"Selected color: RGB(0,255,0)"

Пример

Давайте создадим флаг, который принимает список строк:

gopackage main

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

type StringList []string

func (s *StringList) String() string {
  return strings.Join(*s, ", ")
}

func (s *StringList) Set(value string) error {
  *s = strings.Split(value, ",")
  return nil
}

func main() {
  var names StringList
  flag.Var(&names, "names", "John,Jane", "comma-separated list of names")
  flag.Parse()

  fmt.Printf("Names: %s\n", names.String())
  fmt.Printf("Count: %d\n", len(names))
}

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

go$ go run main.go -names Alice,Bob,Charlie
"Names: Alice, Bob, Charlie"
"Count: 3"

Пример

Давайте создадим флаг с валидацией значений:

gopackage main

import (
  "flag"
  "fmt"
  "strconv"
)

type Port struct {
  Value int
}

func (p *Port) String() string {
  return strconv.Itoa(p.Value)
}

func (p *Port) Set(value string) error {
  port, err := strconv.Atoi(value)
  if err != nil {
    return err
  }
  if port < 1 || port > 65535 {
    return fmt.Errorf("port must be between 1 and 65535")
  }
  p.Value = port
  return nil
}

func main() {
  var port Port
  flag.Var(&port, "port", "8080", "server port number (1-65535)")
  flag.Parse()

  fmt.Printf("Server port: %d\n", port.Value)
}

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

go$ go run main.go -port 9090
"Server port: 9090"

$ go run main.go -port 70000
"invalid value \"70000\" for flag -port: port must be between 1 and 65535"

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

  • функцию flag.String,
    которая определяет строковый флаг
  • функцию flag.Int,
    которая определяет целочисленный флаг
  • функцию flag.Bool,
    которая определяет булев флаг
  • функцию flag.Parse,
    которая разбирает переданные аргументы командной строки