источник
Я думал о том, как сделать так, чтобы людям было легче поддерживать состояние ежедневного обучения и непрерывной работы. Ведение блога — это один из способов, но не каждый день есть что-то, о чем стоит писать. Иногда технология сложнее.При написании блога я часто пишу, что считаю, что мое понимание предвзято, или детали не до конца поняты.Я должен проверить информацию, а затем продолжить писать после того, как я ее пойму, и скоро. Это может привести к тому, что блог займет слишком много времени.
я просматриваю каждый деньдумаю нет,НаггетсиGithubВ процессе я нашел несколько хороших идей, таких какJS Вопрос дня,Ежедневная библиотека NodeJS,один вопрос интервью в деньИ т. д. и т. д.GitHub.com/par РО-ИТ/Арвин…В этом репозитории собраны небольшие библиотеки NodeJS, увидеть по одной в день не мечта! Это также мое вдохновение для этой серии. Я планирую изучать библиотеку Go каждый день и публиковать вводный пост в блоге. Одна банка в день, конечно, идеальна, и я рассчитываю на 3-5 в неделю.
Сегодня первый день, начнем с базовой библиотеки --- стандартная библиотека в Goflag
.
Введение
flag
Используется для разбора параметров командной строки. Параметры командной строки должны быть знакомы детям, имеющим опыт работы с Unix-подобными системами. например командаls -al
Список сведений обо всех файлах и каталогах в текущем каталоге, где-al
являются параметрами командной строки.
Параметры командной строки очень распространены в реальной разработке, особенно при написании инструментов.
- Укажите путь к файлу конфигурации, например
redis-server ./redis.conf
с файлом конфигурации в текущем каталогеredis.conf
Запустите сервер Redis; - Настройте некоторые параметры, такие как
python -m SimpleHTTPServer 8080
Запустите HTTP-сервер, прослушивающий порт 8080. Если не указано, по умолчанию будет прослушиваться порт 8000.
быстрый в использовании
Первым шагом в изучении библиотеки, конечно же, является ее использование. давайте сначала посмотримflag
Основное использование библиотеки:
package main
import (
"fmt"
"flag"
)
var (
intflag int
boolflag bool
stringflag string
)
func init() {
flag.IntVar(&intflag, "intflag", 0, "int flag value")
flag.BoolVar(&boolflag, "boolflag", false, "bool flag value")
flag.StringVar(&stringflag, "stringflag", "default", "string flag value")
}
func main() {
flag.Parse()
fmt.Println("int flag:", intflag)
fmt.Println("bool flag:", boolflag)
fmt.Println("string flag:", stringflag)
}
Вы можете сначала скомпилировать программу, а затем запустить (я использую Win10 + Git Bash):
$ go build -o main.exe main.go
$ ./main.exe -intflag 12 -boolflag 1 -stringflag test
вывод:
int flag: 12
bool flag: true
string flag: test
Если параметр не установлен, соответствующая переменная примет значение по умолчанию:
$ ./main.exe -intflag 12 -boolflag 1
вывод:
int flag: 12
bool flag: true
string flag: default
Вы можете увидеть параметры, которые не установленыstringflag
значение по умолчаниюdefault
.
также можно использовать напрямуюgo run
, эта команда сначала скомпилирует программу для создания исполняемого файла, а затем выполнит файл, передав другие параметры в командной строке программе.
$ go run main.go -intflag 12 -boolflag 1
можно использовать-h
Отобразить справочную информацию о параметрах:
$ ./main.exe -h
Usage of D:\code\golang\src\github.com\darjun\cmd\flag\main.exe:
-boolflag
bool flag value
-intflag int
int flag value
-stringflag string
string flag value (default "default")
Подводя итог, используйтеflag
Общие шаги для библиотеки:
- Определите некоторые глобальные переменные для хранения значения параметра, как здесь
intflag/boolflag/stringflag
; - существует
init
используемый методflag.TypeVar
параметры определения метода, здесьType
может быть базовым типомInt/Uint/Float64/Bool
, а также интервал времениtime.Duration
. При определении адреса переменной, имени опции, значения по умолчанию и справочной информации; - существует
main
вызов методаflag.Parse
отos.Args[1:]
варианты разбора. так какos.Args[0]
Для пути к исполняемой программе он будет исключен.
будь осторожен:
flag.Parse
метод должен вызываться после определения всех опций, иflag.Parse
Опции не могут быть определены после вызова. Если вы будете следовать предыдущим шагам, в принципе проблем не будет.
так какinit
Выполнять перед всем кодом, поместить определения опций вinit
середина,main
выполнять в функцииflag.Parse
Все параметры уже определены.
формат опции
flag
Библиотека поддерживает три формата параметров командной строки.
-flag
-flag=x
-flag x
-
и--
можно использовать, они работают одинаково. Некоторые библиотеки используют-
для коротких вариантов,--
Указывает на длинные варианты. Условно говоря,flag
Легче в использовании.
Первая форма поддерживает только логические параметры, которые отображаются какtrue
, не отображается как значение по умолчанию.
Третья форма не поддерживает логические параметры. Потому что логические параметры этой формы могут неожиданно вести себя в Unix-подобных системах. См. следующую команду:
cmd -x *
в,*
является подстановочным знаком оболочки. Логическая опция, если есть файл с именем 0, false-x
возьметfalse
. И наоборот, логические параметры-x
возьметtrue
. И эта опция потребляет аргумент.
Если вы хотите отобразить, установите логическую опцию наfalse
, использовать только-flag=false
эта форма.
Обнаружен первый аргумент, не являющийся опцией (то есть не заканчивающийся на-
и--
начало) или конец--
, синтаксический анализ останавливается. Запустите следующую программу:
$ ./main.exe noflag -intflag 12
выведет:
int flag: 0
bool flag: false
string flag: default
потому что при разборе встречаетсяnoflag
просто стоп, следующие варианты-intflag
не разобран. Таким образом, все параметры принимают значения по умолчанию.
Запустите следующую программу:
$ ./main.exe -intflag 12 -- -boolflag=true
выведет:
int flag: 12
bool flag: false
string flag: default
Параметры анализируются в первую очередьintflag
, установите его значение равным 12. встретиться--
После завершения синтаксического анализа происходит следующее--boolflag=true
не анализируется, поэтомуboolflag
значение опции по умолчаниюfalse
.
Если после завершения синтаксического анализа все еще есть аргументы командной строки,flag
библиотека будет храниться черезflag.Args
Метод возвращает часть этих параметров.
в состоянии пройтиflag.NArg
метод для получения количества неразрешенных аргументов,flag.Arg(i)
местоположение доступаi
(на основе 0).
Доступ к количеству опций также можно получить, позвонивflag.NFlag
способ получения.
Немного изменим приведенную выше программу:
func main() {
flag.Parse()
fmt.Println(flag.Args())
fmt.Println("Non-Flag Argument Count:", flag.NArg())
for i := 0; i < flag.NArg(); i++ {
fmt.Printf("Argument %d: %s\n", i, flag.Arg(i))
}
fmt.Println("Flag Count:", flag.NFlag())
}
Скомпилируйте и запустите программу:
$ go build -o main.exe main.go
$ ./main.exe -intflag 12 -- -stringflag test
вывод:
[-stringflag test]
Non-Flag Argument Count: 2
Argument 0: -stringflag
Argument 1: test
Разобрать встречу--
После завершения остальные параметры-stringflag test
Сохранить какflag
, пройти можноArgs/NArg/Arg
и другие способы доступа.
Целочисленные значения параметров могут принимать форму 1234 (десятичное), 0664 (восьмеричное) и 0x1234 (шестнадцатеричное) и могут быть отрицательными. Фактическиflag
используется внутриstrconv.ParseInt
способ разобрать строку наint
.
Итак, в теории,ParseInt
Любой принятый формат подходит.
Значения булевых опций могут быть:
- ценность
true
: 1, т, Т, истина, ИСТИНА, Истина; - ценность
false
: 0, f, F, ложь, ЛОЖЬ, Ложь.
Другой способ определения параметров
Выше мы ввели использованиеflag.TypeVar
Чтобы определить параметры, этот метод требует, чтобы мы сначала определили переменную, а затем адрес переменной.
Другой способ - позвонитьflag.Type
(вType
возможноInt/Uint/Bool/Float64/String/Duration
etc) автоматически назначит нам переменную, возвращая адрес этой переменной. Использование аналогично предыдущему способу:
package main
import (
"fmt"
"flag"
)
var (
intflag *int
boolflag *bool
stringflag *string
)
func init() {
intflag = flag.Int("intflag", 0, "int flag value")
boolflag = flag.Bool("boolflag", false, "bool flag value")
stringflag = flag.String("stringflag", "default", "string flag value")
}
func main() {
flag.Parse()
fmt.Println("int flag:", *intflag)
fmt.Println("bool flag:", *boolflag)
fmt.Println("string flag:", *stringflag)
}
Скомпилируйте и запустите программу:
$ go build -o main.exe main.go
$ ./main.exe -intflag 12
выведет:
int flag: 12
bool flag: false
string flag: default
Это в основном то же самое, что и предыдущий метод, за исключением того, что при использовании его необходимо разыменовывать.
Расширенное использование
определить короткие параметры
flag
Библиотека не поддерживает короткие параметры, но это можно сделать, установив разные параметры для одной и той же переменной. То есть оба варианта используют одну и ту же переменную.
Поскольку порядок инициализации не определен, они должны иметь одинаковое значение по умолчанию. В противном случае поведение не определено, если этот параметр не передан.
package main
import (
"fmt"
"flag"
)
var logLevel string
func init() {
const (
defaultLogLevel = "DEBUG"
usage = "set log level value"
)
flag.StringVar(&logLevel, "log_type", defaultLogLevel, usage)
flag.StringVar(&logLevel, "l", defaultLogLevel, usage + "(shorthand)")
}
func main() {
flag.Parse()
fmt.Println("log level:", logLevel)
}
Скомпилируйте и запустите программу:
$ go build -o main.exe main.go
$ ./main.exe -log_type WARNING
$ ./main.exe -l WARNING
Используйте как длинные, так и короткие параметры для вывода:
log level: WARNING
Если эта опция не передана, выводится значение по умолчанию:
$ ./main.exe
log level: DEBUG
интервал времени парсинга
Помимо возможности использовать примитивные типы в качестве опций,flag
Библиотека также поддерживаетtime.Duration
Тип, который является временным интервалом. Для временных интервалов поддерживается множество форматов, таких как «300 мс», «-1,5 ч», «2 ч 45 мин» и т. д.
Единица времени может быть ns/us/ms/s/m/h/day и т.д. Фактическиflag
будет вызываться внутреннеtime.ParseDuration
. Конкретные поддерживаемые форматы см.time(требуется fq) Документация к библиотеке.
package main
import (
"flag"
"fmt"
"time"
)
var (
period time.Duration
)
func init() {
flag.DurationVar(&period, "period", 1*time.Second, "sleep period")
}
func main() {
flag.Parse()
fmt.Printf("Sleeping for %v...", period)
time.Sleep(period)
fmt.Println()
}
Согласно входящим параметрам командной строкиperiod
, программа засыпает соответствующее время, по умолчанию 1 секунда. Скомпилируйте и запустите программу:
$ go build -o main.exe main.go
$ ./main.exe
Sleeping for 1s...
$ ./main.exe -period 1m30s
Sleeping for 1m30s...
пользовательские параметры
Помимо использованияflag
Тип параметра, предоставляемый библиотекой, мы также можем настроить тип параметра. Разберем кейсы, представленные в стандартной библиотеке:
package main
import (
"errors"
"flag"
"fmt"
"strings"
"time"
)
type interval []time.Duration
func (i *interval) String() string {
return fmt.Sprint(*i)
}
func (i *interval) Set(value string) error {
if len(*i) > 0 {
return errors.New("interval flag already set")
}
for _, dt := range strings.Split(value, ",") {
duration, err := time.ParseDuration(dt)
if err != nil {
return err
}
*i = append(*i, duration)
}
return nil
}
var (
intervalFlag interval
)
func init() {
flag.Var(&intervalFlag, "deltaT", "comma-seperated list of intervals to use between events")
}
func main() {
flag.Parse()
fmt.Println(intervalFlag)
}
Сначала определите новый тип, здесь определите типinterval
.
Новый тип должен реализоватьflag.Value
интерфейс:
// src/flag/flag.go
type Value interface {
String() string
Set(string) error
}
вString
метод для форматирования значения этого типа,flag.Parse
Когда метод встречает параметр пользовательского типа во время выполнения, он вызывает переменную этого типа со значением параметра в качестве параметра.Set
метод.
здесь будет,
Отдельные временные интервалы анализируются и сохраняются в срезе.
Определения опций пользовательского типа должны использоватьflag.Var
метод.
Скомпилируйте и выполните программу:
$ go build -o main.exe main.go
$ ./main.exe -deltaT 30s
[30s]
$ ./main.exe -deltaT 30s,1m,1m30s
[30s 1m0s 1m30s]
Если указанное значение опции недопустимо,Set
метод возвращаетerror
значение типа,Parse
Выполнение завершается, печатая ошибки и используя справку.
$ ./main.exe -deltaT 30x
invalid value "30x" for flag -deltaT: time: unknown unit x in duration 30x
Usage of D:\code\golang\src\github.com\darjun\go-daily-lib\flag\self-defined\main.exe:
-deltaT value
comma-seperated list of intervals to use between events
Разобрать строку в программе
Иногда параметры не передаются в командной строке. Например, чтение из таблицы конфигурации или сгенерированное программой. В это время вы можете использоватьflag.FlagSet
struct для анализа этих параметров.
На самом деле то, что мы называли ранееflag
Методы библиотеки будут вызываться косвенноFlagSet
метод структуры.flag
Библиотека определяетFlagSet
глобальная переменная типаCommandLine
Специально для разбора параметров командной строки.
ранее называлсяflag
Методы библиотеки просто для удобства, они вызываются внутриCommandLine
Соответствующий метод для:
// src/flag/flag.go
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
func Parse() {
CommandLine.Parse(os.Args[1:])
}
func IntVar(p *int, name string, value int, usage string) {
CommandLine.Var(newIntValue(value, p), name, usage)
}
func Int(name string, value int, usage string) *int {
return CommandLine.Int(name, value, usage)
}
func NFlag() int { return len(CommandLine.actual) }
func Arg(i int) string {
return CommandLine.Arg(i)
}
func NArg() int { return len(CommandLine.args) }
Аналогично, мы также можем создать свой собственныйFlagSet
введите переменную для анализа параметров.
package main
import (
"flag"
"fmt"
)
func main() {
args := []string{"-intflag", "12", "-stringflag", "test"}
var intflag int
var boolflag bool
var stringflag string
fs := flag.NewFlagSet("MyFlagSet", flag.ContinueOnError)
fs.IntVar(&intflag, "intflag", 0, "int flag value")
fs.BoolVar(&boolflag, "boolflag", false, "bool flag value")
fs.StringVar(&stringflag, "stringflag", "default", "string flag value")
fs.Parse(args)
fmt.Println("int flag:", intflag)
fmt.Println("bool flag:", boolflag)
fmt.Println("string flag:", stringflag)
}
NewFlagSet
Метод имеет два параметра, первый параметр — это имя программы, которое отображается при выводе справки или ошибок. Второй параметр что делать при разборе ошибок, есть несколько вариантов:
-
ContinueOnError
: продолжить синтаксический анализ после возникновения ошибки,CommandLine
использовать эту опцию; -
ExitOnError
: вызывается при ошибкеos.Exit(2)
выйти из программы; -
PanicOnError
: паника при возникновении ошибки.
посмотриflag
Соответствующий код в библиотеке:
// src/flag/flag.go
func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true
f.args = arguments
for {
seen, err := f.parseOne()
if seen {
continue
}
if err == nil {
break
}
switch f.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
os.Exit(2)
case PanicOnError:
panic(err)
}
}
return nil
}
с прямым использованиемflag
Подход библиотеки немного отличается,FlagSet
перечислитьParse
Метод должен отображать входящий фрагмент строки в качестве параметра. так какflag.Parse
звонил внутреннеCommandLine.Parse(os.Args[1:])
.
Пример кода находится вGitHubвверх.
Ссылаться на
- flagбиблиотечная документация
я
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~
Эта статья опубликована в блогеOpenWriteвыпуск!