Accepted proposal: range over all command-line flags

Go’s proposal for package flag was accepted on July 23, 2026. It fixes an awkward case in programs that read the same setting from command-line flags, environment variables, and defaults.

Suppose a server has a -debug flag whose default is false:

fs := flag.NewFlagSet("serve", flag.ContinueOnError)
debug := fs.Bool("debug", false, "enable debug logging")

if err := fs.Parse(args); err != nil {
    return err
}

The server also reads APP_DEBUG. A command-line flag should win over the environment variable, and the environment variable should win over the default. If the user runs the server with -debug=false while APP_DEBUG=true, the server must keep debug mode off. But *debug is false both when the flag was omitted and when the user explicitly set it to false. The parsed value alone cannot distinguish those cases.

The flag package knows which flags were set, but today it exposes that information through two callbacks. Visit walks only the flags that were set successfully. VisitAll walks every declared flag. Code that fills unset flags from the environment has to combine both:

func applyEnv(fs *flag.FlagSet) error {
    alreadySet := make(map[string]bool)
    fs.Visit(func(f *flag.Flag) {
        alreadySet[f.Name] = true
    })

    var applyErr error
    fs.VisitAll(func(f *flag.Flag) {
        if applyErr != nil || alreadySet[f.Name] {
            return
        }

        key := "APP_" + strings.ToUpper(
            strings.ReplaceAll(f.Name, "-", "_"),
        )
        value, ok := os.LookupEnv(key)
        if !ok {
            return
        }
        if err := fs.Set(f.Name, value); err != nil {
            applyErr = fmt.Errorf(
                "set flag -%s from %s: %w", f.Name, key, err,
            )
        }
    })
    return applyErr
}

The first pass records the flags found by Visit. The second pass visits everything and looks up an environment variable only when the name is absent from that map. applyErr sits outside the callback because the callback…

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论