dougu1990 2018-03-09 12:06
浏览 99
已采纳

重新定义Golang标志

I have flags that may be defined in multiple components. Its not possible to know if a component has already defined a flag, as such if two components Foo and Bar require flag Zed, but Foo and Bar must define flag Zed. In this case, Go's flag's will panic with an error flag redefined.

Is there any way to optionally initialize a flag only if it hasn't been initialized elsewhere? Or alternatively check if a flag has already been set and if it has then lookup the flag value?

The only way I see to do this is with something like this:

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

But this is incredibly ugly (and not sure how well this will work). Any thoughts on a better way to go about this?

  • 写回答

1条回答 默认 最新

  • dqsvf28682 2018-03-09 13:47
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?