A custom flag parser converts raw command-line arguments into typed configuration values. It accepts a configuration pointer and argument slice, then updates the original configuration while parsing. section 4.2.3 section 4.2
Build the parser around a map of flag names to type-specific setter functions:
- Bind each name to a parser closure, such as "url": stringVar(&c.url) and "n": intVar(&c.n). section 4.2.3
- Wrap conversion failures with fmt.Errorf and %w so callers retain the original error, including strconv.ErrSyntax from Atoi. section 4.2.3
Configuration-driven parsing
Given a config containing url, n, c, and rps fields, parseArgs binds "url" to stringVar(&c.url) and the numeric flags to intVar closures. Each closure retains its field pointer and assigns the parsed value, leaving the configuration ready for the command-line tool. section 4.2.3
Listing 4.3 Flag parser (hit/cmd/hit/config.go)
package main
import (
"fmt"
"strings"
. . .
)
type config struct {
url string
n int
c int
rps int
}
func parseArgs(c *config, args []string) error {
flagSet := map[string]parseFunc{ #1
"url": stringVar(&c.url), #2
"n": intVar(&c.n), #3
"c": intVar(&c.c), #3
"rps": intVar(&c.rps), #3
}
for _, arg := range args {
name, val, _ := strings.Cut(arg, "=") #4
name = strings.TrimPrefix(name, "-") #5
setVar, ok := flagSet[name] #6
if !ok {
return fmt.Errorf(
"flag provided but not defined: -%s",
name,
)
}
if err := setVar(val); err != nil { #7
return fmt.Errorf( #8
"invalid value %q for flag -%s: %w", #8
val, name, err, #8
) #8
}
}
return nil
}
Inspect the complete parseArgs implementation, including configuration fields, flag bindings, argument handling, lookup, and error paths. section 4.2.3
