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() 中 |
在 main 中 Parse 之前定义也可以 |
| 布尔标志的特殊行为 | -verbose 就是 -verbose true,不需要 =true |
flag.Parse() 在多个 goroutine |
应在 main 启动 goroutine 前调用 |