【问题标题】:How to access flags outside of main package?如何访问主包之外的标志?
【发布时间】:2017-05-16 17:00:51
【问题描述】:

我们在 main.go 中 parse flags 当然是在 main 包中。然后我们有另一个包,我们想在其中读取一些标志的值。

flags.Args() 工作正常,它将返回所有非标志值。

但我无法弄清楚如何读取除 main 之外的包中标志的已解析值。

有可能吗?

谢谢

美国

【问题讨论】:

    标签: go flags


    【解决方案1】:

    我最近有同样的需求,我想要一个避免在 init 函数中重复调用 flag.Parse 的解决方案。

    仔细阅读flag 包,我发现Lookup(name string) 返回一个Flag,它有一个Value。每个内置的 Value 都实现了flag.Getter 接口。调用链如下所示:

    flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
    

    如果您输入错误的标志名称或使用错误的类型,您会收到运行时错误。我将查找包装在一个函数中,我在需要的地方直接调用该函数,因为查找和获取方法很快,而且该函数不经常调用。所以主包声明了这个标志。

    // main.go
    package main
    
    import "flag"
    
    var httplog = flag.Bool("httplog", false, "Log every HTTP request and response.")
    
    func main() {
        flag.Parse()
        // ...
    }
    

    而除了标志名之外与main解耦的实用程序包读取标志值。

    // httpdiag.go
    package utility
    
    import "flag"
    
    func logging() bool {
        return flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
    }
    

    【讨论】:

      【解决方案2】:

      您可以将存储标志的var定义在单独的包中,作为导出变量,然后在主包中调用标志解析​​来使用该变量,如下所示:

      mypackage/const.go

      var (
          MyExportedVar string
      )
      

      ma​​inpackage/main.go

      func init() {
          flag.StringVar(&mypackage.MyExportedVar, "flagName", "defaultValue", "usage")
      
          flag.Parse()
      }
      

      这样,每个人都可以访问该标志,包括该包本身。

      注意: 这仅适用于导出的变量。

      【讨论】:

      • 这个!应该被接受的答案。很好,它不会在模块之间引入标志名依赖关系,并保持标志定义和解析到单个模块。
      【解决方案3】:

      您可以在该包中定义标志并在func init()中调用flag.Parse()flag.Parse可以被多次调用。

      但是,如果你想从多个包中访问标志的值,你必须公开它或创建一个公开的函数来检查它。

      例如:

      // pkgA
      var A  = flag.Bool("a", false, "why a?")
      
      func init() {
          flag.Parse()
      }
      
      // main package
      func main() {
          flag.Parse()
          if *pkgA.A {
              // stuff
          }
      }
      

      如果你想重新解析参数,也可以使用FlagSet.Parse(os.Args)

      【讨论】:

        【解决方案4】:

        当你解析你的标志时,将它们解析成以初始大写开头的全局变量,因此它们是公共的,例如

        package main
        
        var Species = flag.String("species", "gopher", "the species we are studying")
        
        func main() {
            flag.Parse()
        }
        

        然后在您的其他包中,您可以将它们称为

        package other
        
        import "/path/to/package/main"
        
        func Whatever() {
            fmt.Println(main.Species)
        }
        

        【讨论】:

        • 我试过这个。问题,然后我得到import cycle not allowed 那是因为其他包在主文件夹下。
        • @Amer 你不能把参数传递给另一个包吗?
        • @OneOfOne,是的,我们可以使用它。我真的很喜欢标志,因为它在一个位置处理默认值和帮助文本。我希望有一种简单的方法可以从主包外部访问标志。但如果不可能的话,也没什么大不了的。我们可能只使用 args 并编写一个自定义帮助器。
        • @Amer 如果你的包只使用了这个标志,你不需要把它放在 main 中,或者只是将标志的值从 main 传递给 pkg,比如pkg.New(flag-value)
        • 谢谢,我知道这是一个很好的解决方案。可能比在非主包中读取 global/env 值更好。但在我们的例子中,main 实例化了另一个包中的另一个类,该类使用工厂模式可以实例化我们需要访问标志的类。所以这意味着我们将不得不稍微传递这个值。这可能有点太多的重构而不是现在的价值。看起来flag.Args() 是要走的路。谢谢@OneOfOne 和尼克!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-15
        • 1970-01-01
        • 2022-12-11
        • 2020-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多