flag
Package flag implements command-line flag parsing.
It provides a mechnism to parse a slice of textual input, which can be used in many situations besides command-line. Here is an example:
// parse the command-line arguments
// For example: go run . -fail 5
var nFail int
flag.IntVar(&nFail, "fail", 12, "number of fail")
flag.Parse() // nFail is 5 in this case
// parse a slice of textual input
var nSuccess int
fs := flag.NewFlagSet("ExampleIntVar", flag.ExitOnError)
fs.IntVar(&nSuccess, "success", 100, "number of success")
fs.Parse([]string{"-success", "500"}) // nSuccess is 500 in this case
We need to register the parsing rules for each “flag” (in a map structure in this case). Then extract the rule and apply it during the parsing process. The mechnism to parse a slice of texts:
- register rules: bind a variable to the expected flag
- register rules: create a Flag structure to store parsing rules
- register rules: add the Flag to FlagSet
- parse input: traverse the slice and parse each flag to corresponding variable
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
// [1] bind a variable to the expected flag
f.Var(newIntValue(value, p), name, usage)
}
func (f *FlagSet) Var(value Value, name string, usage string) {
...
// [2] create a Flag to store parsing rules
flag := &Flag{name, usage, value, value.String()}
...
// [3] add the Flag to FlagSet
f.formal[name] = flag
}
type intValue int
func newIntValue(val int, p *int) *intValue {
*p = val
return (*intValue)(p)
}
func (i *intValue) Set(s string) error {/* parsing rules */}
func (i *intValue) String() string { return strconv.Itoa(int(*i)) }
type Value interface {
String() string
Set(string) error
}
// [4] Parse flags from input list.
func (f *FlagSet) Parse(arguments []string) error {
...
for {
...
flag, ok := f.formal[name]
err := flag.Value.Set(value)
}
}
It works like net/http that registers handler functions in a map structure and extract corresponding handler from the map when a http request comes in.
// register handlers and start the service
http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
// src code
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
...
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
...
}
func ListenAndServe(addr string, handler Handler) error {
...
for {
...
h, _ := mux.m[path]
h(w, r)
...
}
}