重新定义了 Golang 标志
Golang flag redefined
我有可以在多个组件中定义的标志。不可能知道组件是否已经定义了标志,因此如果两个组件 Foo 和 Bar 需要标志 Zed,但 Foo 和 Bar 必须定义标志 Zed。在这种情况下,Go 的标志将因重新定义错误标志而恐慌。
有没有什么方法可以选择性地初始化一个标志,前提是它还没有在其他地方初始化过?或者检查是否已经设置了标志,如果已经设置则查找标志值?
我看到的唯一方法是使用这样的东西:
var fooFlag *string
func init() {
if flag.Lookup("foo") == nil {
fooFlag = flag.String("foo", "", "some flag foo")
}
}
func initFlags() {
if fooFlag == nil && flag.Lookup("foo") != nil {
temp := (*flag.Lookup("foo")).Value.(flag.Getter).Get().(string)
fooFlag = &temp
}
}
func main() {
flag.Parse()
initFlags()
...
}
但这非常丑陋(并且不确定它的效果如何)。有没有更好的方法来解决这个问题?
不幸的是,标准库没有更简单的方法,因为每个标志只能注册一次。我们将了解如何简化您的代码,以及如何避免这种模式。
Flag.FlagSet 没用
flag.FlagSet
is not a solution, it was designed to support subcommands (see this question for an example: Defining Independent FlagSets in GoLang).
的用法
为了证明它为什么没有帮助:假设您有 2 个标志集(一个可能是 flag
包的 detaulf)。第一个标志集可能包含 "foo"
和 "bar"
标志,第二个标志集可能包含 "foo"
和 "baz"
标志。如果用户为所有 3 个提供值会发生什么?调用第一个flagset的FlagSet.Parse()
会报错:
flag provided but not defined: -baz
同样,第二个标志集的 FlagSet.Parse()
也会报告未定义 -bar
的错误。
简化您的代码
如果你想保持你的方法,请注意你可以通过使用标志变量 (flag.StringVar()
) 来简化你的代码,然后在 initFlags()
中你可以简单地得到一个 string
值并像这样分配给您的标志变量:
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()
...
}
此外,如果你想像这样处理多个标志,那么你应该创建辅助函数来不重复(现在更少"ugly")代码:
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)
}
并且使用上面的助手,注册 3 个标志变量就像:
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()
...
}
解决方案?
显而易见的解决方案是使用不同的名称。如果通用名称可能会发生冲突,您可以在它们前面加上前缀,例如与包名称或其他东西。但是您应该使用不同的、不同的、唯一的名称。
想一想。如果你想使用相同的标志(name 相同),你为什么要在两个不同的地方尝试注册它两次?
如果您确实想在多个地方使用同一个标志,那么 "outsource" 标志变量及其注册。例如。创建一个包来处理这个问题,并从需要它的两个地方引用这个包。或者确保将标志变量的值分配到需要的地方。
我有可以在多个组件中定义的标志。不可能知道组件是否已经定义了标志,因此如果两个组件 Foo 和 Bar 需要标志 Zed,但 Foo 和 Bar 必须定义标志 Zed。在这种情况下,Go 的标志将因重新定义错误标志而恐慌。
有没有什么方法可以选择性地初始化一个标志,前提是它还没有在其他地方初始化过?或者检查是否已经设置了标志,如果已经设置则查找标志值?
我看到的唯一方法是使用这样的东西:
var fooFlag *string
func init() {
if flag.Lookup("foo") == nil {
fooFlag = flag.String("foo", "", "some flag foo")
}
}
func initFlags() {
if fooFlag == nil && flag.Lookup("foo") != nil {
temp := (*flag.Lookup("foo")).Value.(flag.Getter).Get().(string)
fooFlag = &temp
}
}
func main() {
flag.Parse()
initFlags()
...
}
但这非常丑陋(并且不确定它的效果如何)。有没有更好的方法来解决这个问题?
不幸的是,标准库没有更简单的方法,因为每个标志只能注册一次。我们将了解如何简化您的代码,以及如何避免这种模式。
Flag.FlagSet 没用
flag.FlagSet
is not a solution, it was designed to support subcommands (see this question for an example: Defining Independent FlagSets in GoLang).
为了证明它为什么没有帮助:假设您有 2 个标志集(一个可能是 flag
包的 detaulf)。第一个标志集可能包含 "foo"
和 "bar"
标志,第二个标志集可能包含 "foo"
和 "baz"
标志。如果用户为所有 3 个提供值会发生什么?调用第一个flagset的FlagSet.Parse()
会报错:
flag provided but not defined: -baz
同样,第二个标志集的 FlagSet.Parse()
也会报告未定义 -bar
的错误。
简化您的代码
如果你想保持你的方法,请注意你可以通过使用标志变量 (flag.StringVar()
) 来简化你的代码,然后在 initFlags()
中你可以简单地得到一个 string
值并像这样分配给您的标志变量:
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()
...
}
此外,如果你想像这样处理多个标志,那么你应该创建辅助函数来不重复(现在更少"ugly")代码:
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)
}
并且使用上面的助手,注册 3 个标志变量就像:
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()
...
}
解决方案?
显而易见的解决方案是使用不同的名称。如果通用名称可能会发生冲突,您可以在它们前面加上前缀,例如与包名称或其他东西。但是您应该使用不同的、不同的、唯一的名称。
想一想。如果你想使用相同的标志(name 相同),你为什么要在两个不同的地方尝试注册它两次?
如果您确实想在多个地方使用同一个标志,那么 "outsource" 标志变量及其注册。例如。创建一个包来处理这个问题,并从需要它的两个地方引用这个包。或者确保将标志变量的值分配到需要的地方。