iTranslated by AI
Replacing the Standard flag Package with pflag
Just another quick tip.
Replacing the Standard flag Package with the pflag Package
The standard Go flag package for evaluating command-line arguments is simple and well-designed, but have you ever wished you could use GNU-style syntax?
For example, wanting to use -f as a shorthand for a --foo parameter, or specifying -a -b -c together as -abc.
The github.com/spf13/pflag package allows you to implement this. You can write it like this:
package main
import (
"fmt"
"github.com/spf13/pflag"
)
func main() {
f := pflag.BoolP("foo", "f", false, "option foo")
b := pflag.BoolP("bar", "b", false, "option bar")
pflag.Parse()
fmt.Println("foo = ", *f)
fmt.Println("bar = ", *b)
}
Running this results in:
$ go run sample1.go
foo = false
bar = false
$ go run sample1.go --foo --bar
foo = true
bar = true
$ go run sample1.go --foo=true
foo = true
bar = false
$ go run sample1.go -fb
foo = true
bar = true
...and you can specify command-line arguments like this.
pflag is compatible with the standard flag, so you can replace it by writing:
package main
import (
"fmt"
flag "github.com/spf13/pflag"
)
func main() {
f := flag.Bool("foo", false, "option foo")
b := flag.Bool("bar", false, "option bar")
flag.Parse()
fmt.Println("foo = ", *f)
fmt.Println("bar = ", *b)
}
However, since the behavior follows the pflag specification:
$ go run sample2.go --foo
foo = true
bar = false
$ go run sample2.go -foo
unknown shorthand flag: 'f' in -foo
Usage of /tmp/go-build421334830/b001/exe/sample2:
--bar option bar
--foo option foo
unknown shorthand flag: 'f' in -foo
As shown above, if you use -foo as an argument, it will complain that it's an unknown shorthand flag (lol).
[Bonus] Setting Custom Command-Line Parameters for go test
I am embarrassed to admit that I only recently learned at the “Distributed Services with Go” Reading Group that you can use the standard flag package to set custom command-line parameters for go test. You can write it like this:
package sample3
import (
"flag"
"testing"
)
var foo = flag.Bool("foo", false, "option foo")
func TestMain(m *testing.M) {
flag.Parse()
m.Run()
}
func TestFlag(t *testing.T) {
if !*foo {
t.Errorf("option foo = %v, want %v.", *foo, true)
}
}
Running this results in:
$ go test --shuffle on
-test.shuffle 1665227879001765953
--- FAIL: TestFlag (0.00s)
sample3_test.go:17: option foo = false, want true.
FAIL
exit status 1
FAIL pflag-sample/sample3.go 0.001s
$ go test --shuffle on --foo
-test.shuffle 1665227866801533228
PASS
ok pflag-sample/sample3.go 0.001s
Note that the specified flags are only valid within the package.
Well, changing test conditions via command-line arguments might not be common, but I thought it was clever how the sample code in Chapter 6 of Distributed Services with Go sets a --debug flag to output trace logs when specified via the command line.
I wondered if I could do this with pflag as well, but it didn't work out. Too bad. Let's use the standard flag for go test.
Discussion