flag默认值是flag.Type(name, defaultValue, usage)的第二个参数,必须显式提供且参与类型校验;用户不传对应flag时,解析后即为该值,并如实显示在-help中。
flag 包设置默认值非常直接:在调用 flag.String、flag.Int、flag.Bool 等函数时,第二个参数就是默认值。它不是“后续赋值”,而是解析逻辑的起点——用户不传该 flag,程序就自动使用这个值,且会如实显示在 -h 或 --help 输出里。
默认值是 flag.Type(name, defaultValue, usage) 的第二个参数,必须提供(Go 类型系统强制要求),哪怕你只想让它为空或零值。
flag.String("output", "", "输出文件路径") —— 空字符串是合法默认值flag.Int("timeout", 30, "超时秒数") —— 30 是默认值,用户不加 -timeout=60 就用 30flag.Bool("dry-run", false, "仅打印操作,不执行") —— 布尔默认值必须显式写 false 或 true,不能省略漏掉默认值会导致编译失败;设成 nil 或未初始化变量则毫无意义——flag 不读你的变量初始值,只认你传进去的那个字面量。
只要用户没在命令行中出现该 flag(比如没写 -v 或 --verbose),flag.Parse() 后取到的值就一定是你写的默认值,不会是零值以外的其他隐式状态。
常见误解:
flag.Bool("debug", false, "...") 中的 false 只是“占位”,其实它决定了 *debug 在未传 -debug 时的精确值flag.BoolVar(&debug, "debug", true, "...") 却希望不传时是 false —— 错,不传时仍是 true
flag 没有三态语义;如需区分,得
flag.Value
package mainimport ( "flag" "fmt" )
func main() { // 注意:这里默认值是 "prod",不是 "" env := flag.String("env", "prod", "运行环境") flag.Parse() fmt.Println("当前环境:", *env) }
运行 go run main.go → 输出 当前环境: prod;运行 go run main.go -env=dev → 输出 当前环境: dev。
flag 本身不自动关联 -v 和 --verbose;你要手动用两个 flag.Bool(或 flag.BoolVar)指向同一个变量,它们才共用默认值。
flag.Bool("v", false, "详细模式"); flag.Bool("verbose", false, "") → 创建两个独立变量,互不影响flag.BoolVar(&verbose, "v", false, "启用详细输出"); flag.BoolVar(&verbose, "verbose", false, "")
这样,-v、--verbose、-v=true、--verbose=true 都生效,且都受同一个默认值控制。
flag 自动生成的帮助文本(-h)会把默认值括在括号里,例如:
-env string
运行环境 (default "prod")
所以,默认值字符串本身应尽量简洁、无歧义。避免写 "(默认: 生产环境)" 这类冗余描述——括号和 default 已由 flag 自动添加,重复写反而导致帮助信息变成:
-env string
运行环境 (default "(默认: 生产环境)")
另外,如果默认值含空格或特殊字符(如 JSON 字符串),建议在文档 usage 字段里额外说明转义规则,因为 flag 不做 shell 层解析。
真正容易被忽略的是:默认值参与类型校验。比如 flag.Int("port", 999999, "...") 编译没问题,但运行时若用户传了 -port=70000,会因超出 int 范围 panic —— 默认值本身也会触发同套校验逻辑,只是发生在编译期常量检查阶段。所以默认值也得是“合法输入”。