使用flag包,是否有一种很好的方法来区分是否传递了字符串标志?
例如,当没有传递标志时,我想将其设置为动态默认值。但是,如果提供了标志,但我想将其设置为空,但值为""
。
目前我正在做以下事情:
flagHost = flag.String(flagHostFlagKey, "", "...")
...
setHostname := false
for _, arg := range os.Args {
if arg == "-"+flagHostFlagKey {
setHostname = true
}
}
if !setHostname {
...
这似乎工作正常,但有点难看。使用标准标志包时有更好的方法吗?
答案 0 :(得分:22)
内置标记类型不支持区分默认值和显式赋值为默认值。但是,flag
包非常灵活,允许您使用flag.Value
界面滚动自己的类型。
这是一个完整的示例,其中包含一个字符串标记,用于记录是否已分配给它。
package main
import (
"flag"
"fmt"
)
type stringFlag struct {
set bool
value string
}
func (sf *stringFlag) Set(x string) error {
sf.value = x
sf.set = true
return nil
}
func (sf *stringFlag) String() string {
return sf.value
}
var filename stringFlag
func init() {
flag.Var(&filename, "filename", "the filename")
}
func main() {
flag.Parse()
if !filename.set {
fmt.Println("--filename not set")
} else {
fmt.Printf("--filename set to %q\n", filename.value)
}
}
这里有一些例子:
$ go run a.go -filename=abc
--filename set to "abc"
$ go run a.go -filename=
--filename set to ""
$ go run a.go
--filename not set
答案 1 :(得分:13)
使用自定义标志类型(此线程中的stringFlag示例)的问题是您稍微打乱了PrintDefaults输出(即--help)。例如,使用字符串username标志和stringFlag servername标志, - help如下所示:
-server value
server:port (default localhost:1234)
-username string
username (default "kimmi")
请注意,就用户而言,这些都是字符串参数,但不同之处在于stringFlag不是字符串。
flag标记集的内部地图包含已声明的标记('正式')和实际设置的标记('实际')。前者可以通过Lookup()获得,虽然后者没有暴露,或者你可以写:
var servername = flag.String("server", "localhost:8129", "server:port")
flag.Parse()
if f := flag.CommandLine.LookupActual("server"); f != nil {
fmt.Printf("server set to %#v\n", f)
} else {
fmt.Printf("server not set\n")
}
似乎你能做的最好,如果你想要一致的PrintDefaults()输出,就是使用Visit提取自己的“实际”视图。 (VisitAll对' formal')做同样的事情:
var servername = flag.String("server", "localhost:8129", "server:port")
flag.Parse()
flagset := make(map[string]bool)
flag.Visit(func(f *flag.Flag) { flagset[f.Name]=true } )
if flagset["server"] {
fmt.Printf("server set via flags\n")
} else {
fmt.Printf("server not explicitly set, using default\n")
}
答案 2 :(得分:4)
使用flag.Visit()
函数:
func isFlagPassed(name string) bool {
found := false
flag.Visit(func(f *flag.Flag) {
if f.Name == name {
found = true
}
})
return found
}
答案 3 :(得分:3)
要为标志使用动态默认值,请使用默认设置为动态值创建标志:
func main() {
flagHost = flag.String(flagHostFlagKey, computedHostFlag(), "...")
flag.Parse()
// *flagHost equals the return value from computedHostFlag() if
// the flag is not specified on the command line.
...
}
使用这种方法,不必检测命令行上是否指定了标志。此外,帮助显示正确的默认值。
如果计算值取决于其他标志或计算成本高,则使用其他答案中建议的方法。
答案 4 :(得分:1)
面对同样的问题,但是带有bool标志的情况甚至很复杂,在这种情况下,computeHostFlag()无法正常工作,因为您可以提供仅创建true或false的标志。 “ type stringFlag struct”类型的解决方案也不是最好的,因为破坏了默认值的想法。
以这种方式解决:解析后创建两组具有不同默认值的标志-只需检查-第一个标志集中的标志与第二个标志集中的标志是否具有相同的值-这意味着该标志值由用户从命令行。如果它们不同-则表示默认情况下设置了该标志。
package main
import (
"fmt"
"flag"
)
func main() {
args := []string{"-foo="}
flagSet1 := flag.NewFlagSet("flagSet1", flag.ContinueOnError)
foo1 := flagSet1.String("foo", "-", ``)
boolFoo1 := flagSet1.Bool("boolfoo", false, ``)
flagSet1.Parse(args)
flagSet2 := flag.NewFlagSet("flagSet2", flag.ContinueOnError)
foo2 := flagSet2.String("foo", "+", ``)
boolFoo2 := flagSet2.Bool("boolfoo", true, ``)
flagSet2.Parse(args)
if *foo1 != *foo2 {
fmt.Println("foo flag set by default")
} else {
fmt.Println("foo flag provided by user")
}
if *boolFoo1 != *boolFoo2 {
fmt.Println("boolfoo flag set by default")
} else {
fmt.Println("boolfoo flag provided by user")
}
}
游乐场:https://play.golang.org/p/BVceE_pN5PO,对于真正的CLI执行,您可以执行以下操作:https://play.golang.org/p/WNvDaaPj585
答案 5 :(得分:0)
我认为一种更可靠的方法是检查命令行参数(os.Args [1:])中是否有任何前缀带有“ prefix” + str的前缀,因此该功能:
func isInSlice(str string, list []string, prefix string) bool {
for _, v := range list {
if strings.HasPrefix(v, prefix + str) {
return true
}
}
return false
}
答案 6 :(得分:0)
FlagSet在我的环境中(
我有一种方法来检查是否使用reflect设置了标志:
import "reflect"
fs := flag.NewFlagSet("the flags", flag.ExitOnError)
flag_name := "host"
host := fs.String(flag_name, "localhost", "specify the host address")
// other flags
fs.Parse(os.Args[1:])
if reflect.Indirect(reflect.ValueOf(fs)).FieldByName("actual").MapIndex(reflect.ValueOf(flag_name)).IsValid() {
fmt.Printf("the host flag is set with value %v", *host)
} else {
fmt.Printf("the host flag is not set")
}
答案 7 :(得分:0)
与https://stackoverflow.com/a/35809400/3567989相同,但具有指向字符串的指针而不是自定义结构。 Container ( width: MediaQuery
.of(context)
.size
.width,
child:
Image.network(my_image_name, fit: BoxFit.fitWidth )
)
如果未设置则为nil,如果未设置则为nil。
*string
答案 8 :(得分:-1)
我发现我们有Lookup()方法:
func isFlagPassed(name string) bool {
rs := flag.Lookup(name)
return rs != nil
}
完整docs