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.Args[1] 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.
CodePudding user response:
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 (
"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)
}
To make your life a whole lot easier, you could use flag
(or pflag
) package to declare input arguments as command-line flags.
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)
}
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 (
"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)
}
}
}
If you want to continue using structs, you can use the reflect
package.
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 demo: https://play.golang.org/p/sch53l2bq4O