2

我是眼镜蛇毒蛇的新手。

我想知道是否有办法从 cli 中排除用户未设置的标志值。所以我的问题是,我的眼镜蛇cmd中有一些具有默认值的可选标志。我想知道如果用户没有设置这些可选标志,是否有办法排除它们被处理?或者从另一个角度来看,有没有办法从标志集中提取用户从 cli 显式更改的标志cmd

这是一个更好地说明我的案例的示例:

var cmd = &cobra.Command{
    Use:   "command [operations]",
    Short: "Perform some commands",
    Run: func(cmd *cobra.Command, args []string) {
        var user User
        err := viper.Unmarshal(&user)
        fmt.Println(err)
        fmt.Println(user)
    },
}

cmd.PersistentFlags().String("name", "", "Your Name (Required)")
cmd.PersistentFlags().String("description", "", "Description")
cmd.PersistentFlags().String("address", "", "Address")
cmd.PersistentFlags().Int("age", -1, "Age")
cmd.MarkPersistentFlagRequired("name")
viper.BindPFlags(cmd.PersistentFlags()) 

因此,假设对于年龄和地址,我希望它们是可选的,并且在传递给 struct 时不传播。所以这意味着,在 cli 中,用户不需要提交ageandaddress标志,这些可选标志的默认值为 nil。但是,Int 和 String 标志是强类型的,因此它们需要默认值(例如:""-1)。结果,当我将命令 pflags 绑定到 viper 并且用户不在 cli 中输入年龄和地址值时,viper 将接收""地址和-1年龄。使用上述方法,默认值将传播到 User 结构。

我想要的是排除用户未设置的标志值。有没有办法让我从接收用户未明确设置的标志值中排除用户结构?

我目前排除未设置标志在 User 结构中处理的解决方案目前是这样的:

  1. 有一个命令标志数组。初始化一个空map[string]interface{}
  2. 遍历数组,并检查标志是否通过flags.Changed("flag"). 如果标志被更改,则将其添加到地图
  3. 将地图转换为 json
  4. 将 json 对象解组为结构

    // inside the Run function of a cobra command
    aMap := make(map[string]interface{})
    flags := cmd.Flags()
    for _, flag := range cmdFlags {
        if flags.Changed(flag) {
            aMap[flag] = viper.Get(flag)
        }
    }
    jsonStr, _ := json.Marshal(aMap)
    var user User
    json.Unmarshal(jsonStr, &user)
    fmt.Println(user)
    

但我想知道是否有比我上面的解决方案更好的选择。最好,我不想更改User结构中的任何内容,因为它是从外部包导入的。

谢谢你。非常感谢您的帮助。

4

1 回答 1

1

假设您的User结构如下所示:

type User struct {
    ...
    age     int
    address string
    ...
}

然后默认情况下结构的初始化User将设置age => 0, address => 0. 所以即使 viper 没有设置默认值。去内部会。

我的建议是:
1.改变用户结构的创建方式

type User struct {
    ...
    age     *int
    address *string
    ...
}
  1. 在 cobra 中nil为这两个字段设置默认值。
    这样你就知道 Cobra 的默认值是不设置值。每当设置值时,它将是一个非nil值。希望有帮助!
于 2019-01-26T18:11:53.657 回答