go - 在 Cobra 命令行工具中,如何为不同的标志使用相同的变量?

标签 go go-modules go-cobra

此示例 Cobra 应用程序,https://github.com/kurtpeek/myCobraApp , 包含一个使用 Cobra 生成器搭建的 Cobra 应用程序,其中包含以下命令:

cobra add serve
cobra add config

目录结构为
.
├── LICENSE
├── cmd
│   ├── config.go
│   ├── root.go
│   └── serve.go
├── go.mod
├── go.sum
└── main.go

config.go , 字符串变量 deviceUUID已定义并绑定(bind)到该命令的标志,默认值为 "configDeviceUUID" :

var deviceUUID string

func init() {
    rootCmd.AddCommand(configCmd)

    // Cobra supports local flags which will only run when this command
    // is called directly, e.g.:
    configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
    fmt.Println("deviceUUID after config init:", deviceUUID)
}

同样,在 serve.go deviceUUID变量绑定(bind)到本地标志:

func init() {
    rootCmd.AddCommand(serveCmd)

    serveCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "serveDeviceUUID", "Device UUID")
    fmt.Println("deviceUUID after serve init:", deviceUUID)
}

问题是如果我运行 config命令未指定 deviceUUID命令行中的标志,它从 serve 中获取默认值命令:
> go run main.go config
deviceUUID after config init: configDeviceUUID
deviceUUID after serve init: serveDeviceUUID
deviceUUID: serveDeviceUUID
config called

似乎正在发生的是 init()每个文件中的函数按字母顺序运行,最后运行的函数设置标志的默认值。

我怎样才能避免这种行为?我想要 config.go 中设置的默认值始终适用于 config命令。 (当然,我可以声明单独的变量,如 configDeviceUUIDserveDeviceUUID ,但这对我来说似乎有点困惑)。

最佳答案

我不知道你为什么会认为那是乱七八糟的。你有一个变量,你把它设置在几个 init功能,所以最后一个设置是保持设置的那个:你对正在发生的事情的解释是正确的。显然,这实际上是两个不同的变量,只是实际上最多使用其中一个。

(假设还有其他命令可以做其他事情,也许这些全局变量都不会被使用。如果 Go 是一种自然更动态的语言,其中一切都在运行时决定,或者如果您使用的是更动态的运行时设置,你可能还没有创建它们。但这不是 Go:Go 充满了静态类型和静态变量,在链接时创建。)

但是,如果您确实只想使用一个全局变量,显而易见的解决方案是选择一些标记值来表示未设置,并将其设为 Cobra 设置的默认值。然后,如果变量在运行命令时保持“未设置”值,您就知道用户没有提供值。

如果空字符串适合作为这样的哨兵——通常就是这种情况——这很容易。您的每个命令都有几行:

if deviceUUID == "" {
    deviceUUID = defaultDeviceUUID
}

你就完成了。

如果 cobra 代码在您这样做时将默认初始化器值保存在某个私有(private)位置,这可能会很好,或者至少对您来说更方便:

configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")


然后当顶级命令决定 config 时,将那些私有(private)的、保存的默认值复制到(单个)全局变量中。将使用子命令,而不是将其保存在私有(private)的某个地方,然后将其复制到当时的(单个)全局变量中 configCmd.Flags().StringVar()函数被调用,但这不是它的实际工作方式。所以:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "", "Device UUID")

加上上面的空字符串测试可能就足够了。请注意,每个 init仍然每次都覆盖(单个、共享和可能从未使用过的)全局变量,但所有变量都将其从初始空字符串值设置为新的空字符串值,保持不变。

关于go - 在 Cobra 命令行工具中,如何为不同的标志使用相同的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60443941/

相关文章:

go - 将 Goroutine 分离为独立进程

Golang API 到 WPA 请求方

go - 在多个线程中运行一个函数

go - 这个命令 'GOFLAGS=-mod=mod' 是做什么的?

go - 如何在 Go 中访问调用堆栈中的变量

go - 为什么 go-get 尝试从远程位置下载本地代码?

go - 编辑多个未发布的 Go 模块的本地副本

Goland 无法使用 Go 1.14 识别我的 vendor 目录

go - 如何提取注册信息?