flag.parse()必须在所有flag定义之后调用,否则后续定义的flag不会被解析;-h和--help需分别注册到同一变量;stringslice不支持自动追加,需自定义flag.value实现;子命令须用独立flagset解析。

flag.Parse() 必须在所有 flag 定义之后调用
参数全为空、*name 始终是 ""、*port 总是 0——这不是 bug,是你把 flag.Parse() 写太早了。它只解析“当时已注册”的 flag,后续声明的变量根本不会被识别。
常见错误写法:
-
flag.Parse()放在main()第一行 - 在
init()里提前调用 - 定义一个 flag,立刻
flag.Parse(),再定义下一个
正确顺序就一条:所有 flag.String()、flag.IntVar() 等调用必须出现在 flag.Parse() 之前,且仅调用一次。解析后才能安全取值,比如 *host 或 cfg.Port。
短选项 -h 和长选项 --help 要分别注册
Go 的 flag 包不自动映射短选项。-h 和 --help 是两个独立 flag,不是同名别名。只注册 "help",-h 会报错 unknown flag: -h。
必须显式绑定到同一变量:
flag.BoolVar(&help, "h", false, "show help")flag.BoolVar(&help, "help", false, "show help")
注册完立即检查:if help { printUsage(); os.Exit(0) }。别等业务逻辑跑完才处理——flag.Parse() 后 -h 不会自动退出,除非你手动拦截。
StringSlice 不支持多次传参自动追加
用 flag.StringSlice("tag", []string{}, ""),然后执行 ./app -tag a -tag b,结果却是 []string{"b"}。原生 StringSlice 是覆盖语义,不是追加。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
要真正支持重复 flag,得自己实现 flag.Value:
- 定义类型
type stringSlice []string - 实现
Set(string) error:里面用append(*s, value) - 实现
String() string:返回strings.Join([]string(*s), ",") - 注册:
flag.Var(&tags, "tag", "add tag (can be repeated)")
漏掉 Set 方法会导致 panic;漏掉空字符串过滤(如 -tag a,,b)会让切片含空元素。
子命令必须用独立 FlagSet 解析
flag.CommandLine.Parse() 无法识别 myapp serve --port 3000 中的 serve——它会被当成未知 flag 报错。Go 原生不支持子命令嵌套。
正确做法是手动切分参数:
- 先调
flag.Parse()解析全局选项(如--version) - 用
flag.Args()拿剩余参数:args := flag.Args() - 取
args[0]判断子命令名,比如"serve" - 创建新集:
serveCmd := flag.NewFlagSet("serve", flag.ContinueOnError) - 解析子命令参数:
serveCmd.Parse(args[1:])(注意索引从1开始)
每个子命令都要有自己的 FlagSet 和独立的 Parse() 调用;复用 flag.Parse() 会失败。
最易被忽略的是执行顺序和作用域边界:flag 注册、Parse、取值三步不能穿插,子命令的参数切分点必须精准,自定义 Value 的 Set 方法一旦缺失就会 panic——这些地方没 warning,只有运行时表现异常。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










