我正在使用 Go 和 Cobra 库构建 CLI。我有以下 JSON,需要在相应的结构中反序列化。 JSON 数组形式的参数:
"[
(stringA, stringB),
stringC
]"
结构
type MyStruct struct {
StringArray []string
}
我正在使用 Cobra 的
StringSicceVarP
如下
cmd.PersistentFlags().StringSliceVarP(&opts.StringParam, "paramname", "", nil, `this is the description`)
但是 cobra 正在将传入的 json 作为一个字符串读取
[(stringA, stringB), stringC]
而我希望数组的长度为 2,这样
StringArray[0]: (stringA, stringB)
和 StringArray[1]:stringC
.
我无法使用
StringSliceVarP
,因为它将基于 ,
进行分割,我不希望这样,因为我的数组字符串本身可能有一个 ,
。
我怎样才能实现这个目标?
我个人建议您不要选择此选项。提供格式化数据通常是通过读取 STDIN 或从文件中完成的。这种解决方案通常更灵活,允许您添加标志来指定文件的格式(JSON、XML 等)。
在参数中提供文件名而不是原始 JSON 字符串可以增加与其他软件更好的互操作性,以及其他好处,例如使用计算机磁盘而不是计算机内存/RAM 来缓冲数据。
我个人的建议是:
但是,如果您坚持使用标志:
Cobra 没有内置对 JSON 结构的支持。但是,pflag包(Cobra使用的标志库)允许您通过
pflag.(*FlagSet).Var()
方法定义要用作标志的自定义值类型。您必须创建一个实现 pflag.Value
接口的新类型:
type Value interface {
String() string
Set(string) error
Type() string
}
要创建自定义 JSON 解析类型,您可以编写以下代码来使用内置
encoding/json
包:
import (
"encoding/json"
)
type JSONFlag struct {
Target interface{}
}
// String is used both by fmt.Print and by Cobra in help text
func (f *JSONFlag) String() string {
b, err := json.Marshal(f.Target)
if err != nil {
return "failed to marshal object"
}
return string(b)
}
// Set must have pointer receiver so it doesn't change the value of a copy
func (f *JSONFlag) Set(v string) error {
return json.Unmarshal([]byte(v), f.Target)
}
// Type is only used in help text
func (f *JSONFlag) Type() string {
return "json"
}
然后要使用这个新的
pflag.Value
兼容类型,您可以编写如下内容:
import (
"fmt"
"github.com/spf13/cobra"
)
type MyStruct struct {
StringArray []string
}
func init() {
var flagMyStringArray []string
var myCmd = &cobra.Command{
Use: "mycmd",
Short: "A brief description of your command",
Run: func(cmd *cobra.Command, args []string) {
myStruct := MyStruct{StringArray: flagMyStringArray}
fmt.Printf("myStruct.StringArray contains %d elements:\n", len(myStruct.StringArray))
for i, s := range myStruct.StringArray {
fmt.Printf("idx=%d: %q", i, s)
}
},
}
rootCmd.AddCommand(myCmd)
myCmd.Flags().Var(&JSONFlag{&flagMyStringArray}, "paramname", `this is the description`)
}
使用示例:
$ go run . mycmd --paramname 'hello'
Error: invalid argument "hello" for "--paramname" flag: invalid character 'h' looking for beginning of value
Usage:
test mycmd [flags]
Flags:
-h, --help help for mycmd
--paramname json this is the description
exit status 1
$ go run . mycmd --paramname '["(stringA, stringB)", "stringC"]'
myStruct.StringArray contains 2 elements:
idx=0: "(stringA, stringB)"
idx=1: "stringC"