将命令行参数转换为用作结构字段的形式。

huangapple go评论97阅读模式
英文:

Converting command line argument to use as struct field

问题

我正在尝试打印一个从终端输入的特定JSON字段(转换为结构体)。

这是我创建的结构体示例,我想将"field1"作为命令行参数,并通过访问解码后的JSON输出将其打印到HTML正文或控制台。

通常我可以这样打印,但我找不到一种将**os.Args1**的值转换为已定义的结构体字段的方法。

type foo struct{ 
    field1 string
    field2 int
}

var res *foo
_=json.NewDecoder(resp.Body).Decode(&res)
fmt.Println(res.field1)

总之,有没有一种将任何字符串变量转换为函数/方法的方法。非常感谢。

修订说明:例如,
我将在终端中写入:

go run main.go "field1"

程序将执行类似于以下操作:

fmt.Fprintf(writer, "option.field is %v", someFuncThatConcatenatesThisTwo("option."+ os.Args[1]))

顺便说一下,有多个字段需要调用。预定义可以解决某些特定情况,但我想了解是否还有其他方法。

英文:

I am trying to print a JSON(converted to struct) field particularly which is taken as input from terminal.

type foo struct{ 
field1 string
field2 int
}

This is struct sample that i created and i want to take "field1" as command-line argument and print it to html body or console by reaching decoded JSON output.

Normally i can print it this way but i couldn't find a way to convert os.Args1 value to field of struct which was already defined.

var res *foo
_=json.NewDecoder(resp.Body).Decode(&res)
fmt.Println(res.field1)

In summary, is there a way to convert any string variable to function/method. Thanks a lot in advance

Rev. note: eg.
i will write to terminal:

go run main.go "field1"

the program will do something like this

fmt.Fprintf(writer, "option.field is %v", someFuncThatConcatenatesThisTwo("option."+ os.Args[1]))

Btw, There is multiple fields to be called. Predefining could solve for a certain case of course but i want to learn is something else.

答案1

得分: 2

总结一下,有没有一种方法可以将任何字符串转换为函数/方法?

我不确定你在这里想要实现什么。这没有任何意义。


通常情况下,要使用命令行参数填充结构字段,你可以按照以下方式进行操作。

package main

import (
    "fmt"
    "log"
    "strconv"
    "os"
)

type Options struct {
    Field1 string
    Field2 int64
}

func main() {
    if len(os.Args) < 2 {
        log.Fatal("missing two required positional arguments: Field1 and Field2")
    }

    opts := &Options{}
    opts.Field1 = os.Args[1]

    var err error
    opts.Field2, err = strconv.ParseInt(os.Args[2], 10, 64)
    if err != nil {
        log.Fatalf("failed to parse integer value: %v", os.Args[2])
    }

    fmt.Println(opts)
}

为了让你的生活更加轻松,你可以使用 flag(或 pflag)包将输入参数声明为命令行标志。

import (
    "flag"
    "fmt"
)

type Options struct {
    Field1 string
    Field2 int
}

var opts Options

func init() {
    flag.StringVar(&opts.Field1, "field1", "", "help message for field1")
    flag.IntVar(&opts.Field2, "field2", 0, "help message for field2")
    flag.Parse()
}

func main() {
   fmt.Println(opts)
}

或者,像 @Jomaar 回答的那样,你可以使用一个辅助库,比如 go-arg,以避免手动声明命令行标志。另一种选择是 go-flags


编辑

经过进一步澄清,似乎你想要使用写入器选择性地写入结构的字段,并且你想要使用位置命令行参数来指定要写入的字段。

在这种情况下,我认为 map 将是一个更合适的数据结构,因为它允许你使用字段的 string 键来简单地引用字段。

import (
	"fmt"
	"os"
)

func main() {
    options := map[string]interface{} {
        "field1": "some-value",
        "field2": 1,
    }

    for _, arg := range os.Args[1:] {
        if val, ok := options[arg]; ok {
            fmt.Println(val)
        }
    }
}

如果你想继续使用结构体,你可以使用 reflect 包。

import (
	"fmt"
	"os"
	"reflect"
)

type Options struct {
	Field1 string
	Field2 int
}

func main() {
	opts := &Options{Field1: "some-value", Field2: 1}

	for _, arg := range os.Args[1:] {
		fmt.Println(getAttr(opts, arg))
	}
}

// copied from https://stackoverflow.com/a/66470232/2410641
func getAttr(obj interface{}, fieldName string) (reflect.Value, error) {
	pointToStruct := reflect.ValueOf(obj) // addressable
	curStruct := pointToStruct.Elem()
	if curStruct.Kind() != reflect.Struct {
		return reflect.Value{}, fmt.Errorf("obj is not a struct")
	}
	curField := curStruct.FieldByName(fieldName) // type: reflect.Value
	if !curField.IsValid() {
		return reflect.Value{}, fmt.Errorf("field not found: %s", fieldName)
	}
	return curField, nil
}

Go Playground 示例:https://play.golang.org/p/sch53l2bq4O

英文:

> In summary, is there a way to convert any string to function/method.

I'm not sure what you're trying to achieve here. It doesn't make any sense.


In general, to populate struct fields using command line args, you could do something like the following.

package main

import (
    &quot;fmt&quot;
    &quot;log&quot;
    &quot;strconv&quot;
    &quot;os&quot;
)

type Options struct {
    Field1 string
    Field2 int64
}

func main() {
    if len(os.Args) &lt; 2 {
        log.Fatal(&quot;missing two required positional arguments: Field1 and Field2&quot;)
    }

    opts := &amp;Options{}
    opts.Field1 = os.Args[1]

    var err error
    opts.Field2, err = strconv.ParseInt(os.Args[2], 10, 64)
    if err != nil {
        log.Fatalf(&quot;failed to parse integer value: %v&quot;, os.Args[2])
    }

    fmt.Println(opts)
}

To make your life a whole lot easier, you could use flag (or pflag) package to declare input arguments as command-line flags.

import (
    &quot;flag&quot;
    &quot;fmt&quot;
)

type Options struct {
    Field1 string
    Field2 int
}

var opts Options

func init() {
    flag.StringVar(&amp;opts.Field1, &quot;field1&quot;, &quot;&quot;, &quot;help message for field1&quot;)
    flag.IntVar(&amp;opts.Field2, &quot;field2&quot;, 0, &quot;help message for field2&quot;)
    flag.Parse()
}

func main() {
   fmt.Println(opts)
}

Or, like @Jomaar answered, you could use a helper library like go-arg to avoid manually declaring command-line flags. Another alternative is go-flags.


Edit

After further clarification, it appears that you want to selectively write the fields of a struct using a writer and you want to use positional command-line arguments to specify which fields to write.

I think map will be a more suitable data structure for storing options in this case since it will allow you to simply refer to fields using their string keys.

import (
	&quot;fmt&quot;
	&quot;os&quot;
)

func main() {
    options := map[string]interface{} {
        &quot;field1&quot;: &quot;some-value&quot;,
        &quot;field2&quot;: 1,
    }

    for _, arg := range os.Args[1:] {
        if val, ok := options[arg]; ok {
            fmt.Println(val)
        }
    }
}

If you want to continue using structs, you can use the reflect package.

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;reflect&quot;
)

type Options struct {
	Field1 string
	Field2 int
}

func main() {
	opts := &amp;Options{Field1: &quot;some-value&quot;, Field2: 1}

	for _, arg := range os.Args[1:] {
		fmt.Println(getAttr(opts, arg))
	}
}

// copied from https://stackoverflow.com/a/66470232/2410641
func getAttr(obj interface{}, fieldName string) (reflect.Value, error) {
	pointToStruct := reflect.ValueOf(obj) // addressable
	curStruct := pointToStruct.Elem()
	if curStruct.Kind() != reflect.Struct {
		return reflect.Value{}, fmt.Errorf(&quot;obj is not a struct&quot;)
	}
	curField := curStruct.FieldByName(fieldName) // type: reflect.Value
	if !curField.IsValid() {
		return reflect.Value{}, fmt.Errorf(&quot;field not found: %s&quot;, fieldName)
	}
	return curField, nil
}

Go Playground demo: https://play.golang.org/p/sch53l2bq4O

huangapple
  • 本文由 发表于 2021年11月5日 16:50:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/69850612.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定