Golang旗帜重新定义

8xiog9wr  于 2023-05-11  发布在  Go
关注(0)|答案(2)|浏览(167)

我有可以在多个组件中定义的标志。不可能知道一个组件是否已经定义了一个标志,例如如果两个组件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()
    ...
}

但这是令人难以置信的丑陋(也不确定这将如何工作)。有什么更好的办法吗?

lmvvr0a8

lmvvr0a81#

不幸的是,标准库没有更简单的方法,因为每个标志只能注册一次。我们将看到如何简化您的代码,以及如何避免这种模式。

Flag,FlagSet没有帮助

flag.FlagSet的使用不是一个解决方案,它被设计为支持子命令(请参阅此问题的示例:Defining Independent FlagSets in GoLang)。
为了说明为什么它没有帮助:让我们假设你有两个标志集(一个可能是flag包的细节)。第一标志集可以包含"foo""bar"标志,并且第二标志集可以包含"foo""baz"标志。如果用户提供了所有3个值,会发生什么?对第一个标志集的FlagSet.Parse()的调用将报告错误:
提供了标记但未定义:- 巴兹
类似地,第二个标志集的FlagSet.Parse()也会报告未定义的-bar错误。

简化代码

如果你想保持你的方法,请注意,你可以通过使用flag vars(flag.StringVar())来简化你的代码,然后在initFlags()中,你可以简单地得到一个string值,并像这样赋值给你的flag变量:

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()
    ...
}

同样,如果你想像这样处理多个标志,那么你应该创建帮助函数来避免重复(现在不那么“丑陋”)的代码:

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)
}

使用上面的helper,注册3个flag变量就像:

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()
    ...
}

解决方案?

显而易见的解决方案是使用不同的名称。如果常用名称可能会冲突,您可以在它们前面加上前缀,例如。包名什么的但是你应该使用不同的、独特的、独特的名字。
想想吧如果你想使用相同的标志(相同的 * 名称 *),为什么你试图注册它两次,在2个不同的地方?
如果您确实想在多个地方使用同一个标志,那么就“外包”标志变量及其注册。例如,创建一个包,将照顾这一点,并从两个地方需要它,引用这个包。或者确保将flag变量的值分布到需要它的地方。

cnwbcb6i

cnwbcb6i2#

我有一个函数,我在单元测试中运行了2次。当我运行我的测试,我得到'标志重新定义'错误。为了解决这个问题,我使用了flag.lookup函数,并检查了是否定义了标志。

func myFunc() {
            var firstParam = new(string)
            var secondParam = new(string)
            if flag.Lookup("param1") == nil {
                firstParam = flag.String("param1", "", "first param")
            }
           if flag.Lookup("param2") == nil {
                secondParam = flag.String("param2", "", "second param")
            }
          flag.Parse()
       }

相关问题