Skip to content
Go
flag — 命令行参数解析

flag — 命令行参数解析

flag 是 Go 内置的命令行参数解析库。Go 的 flag 使用 POSIX 风格:-flag value--flag value,也支持 -flag=value


1. 定义标志

方式一:返回指针

var (
    name    = flag.String("name", "default", "your name")
    age     = flag.Int("age", 0, "your age")
    verbose = flag.Bool("verbose", false, "verbose output")
)

方式二:绑定到已有变量

var (
    name    string
    age     int
    verbose bool
)

func init() {
    flag.StringVar(&name, "name", "default", "your name")
    flag.IntVar(&age, "age", 0, "your age")
    flag.BoolVar(&verbose, "verbose", false, "verbose output")
}

💡 规范:标志名建议小写 + 连字符(server-addr),帮助信息清晰说明用途和默认值。


2. 解析与使用

func main() {
    flag.Parse()  // ← 必须调用!

    fmt.Println("name:", *name)   // 返回指针的方式需要解引用
    fmt.Println("age:", age)      // 绑定到变量的方式直接使用
}

3. 非标志参数

flag.Parse()

// 返回非标志参数
args := flag.Args()             // []string
fmt.Println("args:", args)

n := flag.NArg()                // 非标志参数个数
fmt.Println("count:", n)

m := flag.NFlag()               // 已设置的标志个数
fmt.Println("flags set:", m)
$ ./app -name alice file1.txt file2.txt
# flag.Args() = ["file1.txt", "file2.txt"]

4. 子命令实现

flag 不直接支持子命令,但可以用 flag.NewFlagSet 手动实现:

func main() {
    if len(os.Args) < 2 {
        fmt.Println("expected 'serve' or 'migrate' subcommand")
        os.Exit(1)
    }

    switch os.Args[1] {
    case "serve":
        serveCmd(os.Args[2:])
    case "migrate":
        migrateCmd(os.Args[2:])
    default:
        fmt.Printf("unknown subcommand: %s\n", os.Args[1])
        os.Exit(1)
    }
}

func serveCmd(args []string) {
    fs := flag.NewFlagSet("serve", flag.ExitOnError)
    port := fs.Int("port", 8080, "server port")
    fs.Parse(args)
    fmt.Println("serving on port", *port)
}

5. 自定义帮助

flag.Usage = func() {
    fmt.Fprintf(os.Stderr, "Usage: %s [options] <args>\n", os.Args[0])
    fmt.Fprintf(os.Stderr, "Options:\n")
    flag.PrintDefaults()
}

6. 🚨 常见陷阱

陷阱 说明
忘记 flag.Parse() 所有标志都是默认值
标志定义在 init() mainParse 之前定义也可以
布尔标志的特殊行为 -verbose 就是 -verbose true,不需要 =true
flag.Parse() 在多个 goroutine 应在 main 启动 goroutine 前调用