Unfortunately there isn't an easier way with the standard library, because every flag may only be registered once. We'll see how we can simplify your code, and also what we can do to avoid this pattern.
Flag.FlagSet doesn't help
The usage of flag.FlagSet
is not a solution, it was designed to support subcommands (see this question for an example: Defining Independent FlagSets in GoLang).
To demonstrate why it doesn't help: let's assume you have 2 flagsets (one may be the detaulf of the flag
package). The first flagset may contain the "foo"
and "bar"
flags, and the second flagset may contain the "foo"
and "baz"
flags. What happens if the user provides values for all 3? The call to FlagSet.Parse()
of the first flagset will report an error:
flag provided but not defined: -baz
And similarly the FlagSet.Parse()
of the second flagset would also report error for undefined -bar
.
Simplifying your code
If you want to keep your approach, note that you can simplify your code by using flag vars (flag.StringVar()
), and then in initFlags()
you can simply get a string
value and assign to your flag variable like this:
var foo string
func init() {
if flag.Lookup("foo") == nil {
flag.StringVar(&foo, "foo", "", "this is foo")
}
}
func initFlags() {
// "foo" does exist: if noone else registered it, then we did
foo = flag.Lookup("foo").Value.(flag.Getter).Get().(string)
}
func main() {
flag.Parse()
initFlags()
...
}
Also if you want to handle multiple flags like this, then you should create helper functions to not repeat the (now less "ugly") code:
func regStringVar(p *string, name string, value string, usage string) {
if flag.Lookup(name) == nil {
flag.StringVar(p, name, value, usage)
}
}
func getStringFlag(name string) string {
return flag.Lookup(name).Value.(flag.Getter).Get().(string)
}
And using the above helpers, registering 3 flag variables is like:
var foo, bar, baz string
func init() {
regStringVar(&foo, "foo", "", "this is foo")
regStringVar(&bar, "bar", "", "this is bar")
regStringVar(&baz, "baz", "", "this is baz")
}
func initFlags() {
foo = getStringFlag("foo")
bar = getStringFlag("bar")
baz = getStringFlag("baz")
}
func main() {
flag.Parse()
initFlags()
...
}
Solution?
The obvious solution would be to use different names. If common names may collide, you may prefix them e.g. with the package name or something. But you should use different, distinct, unique names.
Think about it. If you want to use the same flag (same by name), why are you attempting to register it twice, at 2 different places?
If you do want to use the same flag from multiple places, then "outsource" the flag variable and its registration. E.g. create a package that will take care of this, and from both places where it's needed, refer to this package. Or make sure to distribute the values of the flag variable to places where it's needed.
NewFlagSet
to have as many sets as you'd like. – AureliaFlagSet
can't be used to solve it, see my answer for a counter-example. – Phrenic