Package flag implements CLI flag parsing.
Specifications
0. Intro
Let’s start with a simple example:
1package main2
3import (4  "flag"5  "fmt"6  "time"7)8
9// 1. Define flag varaibles10var (11  host       string12  port       int13  isTestMode bool14  timeout    time.Duration15)16 collapsed lines
16
17func main() {18  // 2. Bind flags to varaibles19  flag.StringVar(&host, "host", "localhost", "db host")20  flag.IntVar(&port, "port", 3306, "db port")21  flag.BoolVar(&isTestMode, "isTest", true, "isTestMode")22  flag.DurationVar(&timeout, "timeout", 5*time.Second, "db timeout")23
24  //3. Parse he command line into the defined flags25  flag.Parse()26
27  fmt.Println("host:", host)28  fmt.Println("port:", port)29  fmt.Println("isTestMode:", isTestMode)30  fmt.Println("timeout:", timeout)31}output:
1❯ go run main.go2host: localhost3port: 33064isTestMode: true5timeout: 5s6
7❯ go run main.go -port 4000 -timeout 30s8host: localhost9port: 400010isTestMode: true11timeout: 30s2. Procedures
- Define flag varaibles
- Bind flags to varaibles
- Parse he command line into the defined flags using flag.Parse()
3. Command line flag syntax
The following forms are allowed:
- -flagor- --flag: only for boolean flags.
- -flag=x: use for all types
- -flag x: for non-boolean flags only
1// isProd is in default true in this example:2❯ go run main.go --isProd false3isProdMode: true4❯ go run main.go --isProd=false5isProdMode: false4. Two types of functions
flag.typeVar v.s. flag.type
1func StringVar(p *string, name string, value string, usage string)2func BoolVar(p *bool, name string, value bool, usage string)3func IntVar(p *int, name string, value int, usage string)4func DurationVar(p *time.Duration, name string, value time.Duration, usage string)5
6func String(name string, value string, usage string) *string7func Bool(name string, value bool, usage string) *bool8func Int(name string, value int, usage string) *int9func Duration(name string, value time.Duration, usage string) *time.Duration1var x int2flag.IntVar(x, "x", 10, "define x")3
4// flag.type5var y = flag.Int("y", 20, "define y")5. Custom type
If we want to define custom type for CLI, we need to implement the Value interface for the new type:
1type Value interface {2  String() string  // print value3  Set(string) error  // set flag value4}5
6type ClusterArray []int7
8func (arr *ClusterArray) Set(val string) error {9  // disable the flag to be set multiple times10  if len(*arr) > 0 {11    return errors.New("cluster flag already set")12  }13  // type convertion14  for _, val := range strings.Split(val, ",") {15    cluster, err := strconv.Atoi(val)23 collapsed lines
16    if err != nil {17      return err18    }19    *arr = append(*arr, cluster)20  }21  return nil22}23
24func (arrs *ClusterArray) String() string {25  str := "["26  for _, s := range *arrs {27    str += strconv.Itoa(s)28  }29  str += "]"30  return str31}32
33func main() {34  var clusters ClusterArray35  flag.Var(&clusters, "clusters", "db clusters")36  flag.Parse()37  fmt.Println("clusters:", clusters)38}output:
1❯ go run main.go -clusters=1,4,62clusters: [1,4,6]3
4❯ go run main.go -clusters=1,2 -clusters=55invalid value "5" for flag -clusters: cluster flag already set6
7❯ go run main.go -clusters=1,2,i8
9invalid value "1,2,i" for flag -clusters: strconv.Atoi: parsing "i": invalid syntax6. Shorthand
1func main() {2  var port int3  flag.IntVar(&port, "p", 3306, "db port (shorthand)")4  flag.IntVar(&port, "port", 3306, "db port")5  flag.parse()6  fmt.Println("port:", port)7}output:
1❯ go run main.go -p 10002port: 10003❯ go run main.go -port 10004port: 1000You might find the complete example of codes in this repo: go-playground
