I am trying to dynamically set a field that is of type interface{}. In all of the cases below the json unmarshals into the correct structure but in the "problem" case the json unmarshals to []interface{}. For that case I am expecting []Person. Why do I get the wrong type for "problem"?
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Employees struct {
Indicator string `json:"indicator"`
Items interface{} `json:"items"`
}
type Person struct {
Name string `json:"name"`
}
func main() {
simple()
easy()
moreDifficult()
problem()
}
var j = []byte(`{"name": "bob"}`)
var jj = []byte(`[{"name": "bob"}, {"name": "jim"}, {"name": "fred"}]`)
func simple() {
p := Person{}
if err := json.Unmarshal(j, &p); err != nil {
fmt.Println(err)
}
fmt.Println("easy:", p, reflect.TypeOf(p))
}
func easy() {
p := []Person{}
if err := json.Unmarshal(jj, &p); err != nil {
fmt.Println(err)
}
fmt.Println("easy:", p, reflect.TypeOf(p))
}
func moreDifficult() {
var j = []byte(`{"indicator": "more difficult"}`)
e := Employees{}
if err := json.Unmarshal(j, &e); err != nil {
fmt.Println(err)
}
fmt.Println("moreDifficult", e.Items, reflect.TypeOf(e.Items))
}
func problem() {
var j = []byte(`{"indicator:": "problem"}`)
e := Employees{}
if err := json.Unmarshal(j, &e); err != nil {
fmt.Println(err)
}
fmt.Println("problem:", e.Items, reflect.TypeOf(e.Items)) // why not []Person???
}
func (e *Employees) UnmarshalJSON(b []byte) error {
type alias Employees
a := &alias{}
if err := json.Unmarshal(b, &a); err != nil {
return err
}
e.Indicator = a.Indicator
var k = jj
if e.Indicator == "more difficult" {
k = j
e.Items = &Person{}
} else {
e.Items = []Person{}
}
return json.Unmarshal(k, &e.Items)
}
https://play.golang.org/p/xQvjMyLTk5i
The problem is that the interface's underlying value is not a pointer:
e.Items = []Person{}
While it's true that you're passing a pointer to the interface itself:
json.Unmarshal(k, &e.Items)
That does not fix the problem of the underlying value being a non-pointer.
var a interface{} = &T{}
var b interface{} = T{}
b = &b
The types of a and b are different and will be handled differently by the unmarshaler, in b's case the unmarshaler will elect to replace the pointed-to value with a map[string]interface{}.
So to fix your immediate problem you can do something like this:
if e.Indicator == "more difficult" {
k = j
e.Items = &Person{}
} else {
e.Items = &[]Person{}
}
return json.Unmarshal(k, e.Items)
Your current problem has absolutely nothing to do with JSON unmarshaling.
You define Items as type interface{}, so obviously, when you inspect it, it will be of type interface{}. If you want it to be of type []Person, simply define it as such:
type Employees struct {
Indicator string `json:"indicator"`
Items []Person `json:"items"`
}
Once you've done that, your test case will yield the expected results. But your Items will still be empty, as your input JSON doesn't have the items field.
Related
I’m looking to iterate through an interfaces keys.
Goal:
I want to implement a kind of middleware that checks for outgoing data (being marshalled to JSON) and edits nil slices to empty slices.
It should be agnostic/generic so that I don't need to specify field names. Ideally I can pass any struct as an interface and replace nil slices with empty slices.
Controller level
type Tag struct {
Name string
}
type BaseModel struct {
ID uuid.UUID
Active bool
}
type Model struct {
BaseModel // embedded struct
Name string
Number int
Tags []Tag
}
newModel, err := GetModel()
if err != nil {
...
}
RespondAsJson(w, newModel)
Middleware / Middle man json responder
It takes an interface to be generic/agnostic and reusable
in many different controllers
//(1) Attempting to use a map
func RespondWithJson(w http.ResponseWriter, data interface{}) {
obj, ok := data.(map[string]interface{})
// (1.1) OK == false
obj, ok := data.(map[interface{}]interface{})
// (1.2) OK == false
var newMap map[string]interface{}
bytes, _ := json.Marshal(&obj)
json.unMarshal(bytes, &newMap)
// (1.3) newMap has no underlying types on fields
// Nil slice of Tags went in, and it comes out as
// value=nil and type=interface{}
}
//(2) Skipping two as I believe this works, I'd like to avoid implementing it though.
//(3)
//(3.1)
RespondWithJson(w, newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(&data) // data = {*interface{} | Model}
if e.Kind() == reflect.Pointer {
e = e.Elem()
// e has a flag of 22, e.Elem() has a flag of 404
}
for i := 0; i < e.NumField(); i++ {
//PANIC: reflect: call of reflect.Value.NumField on interface Value
...
}
}
//(3.2)
// Reference: https://go.dev/blog/laws-of-reflection (third law)
RespondWithJson(w, newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(data) // data = {interface{} | Model}
if e.Kind() == reflect.Pointer {
e = e.Elem()
}
for i := 0; i < e.NumField(); i++ {
field := e.Field(i)
if field.Kind() == reflect.Slice && field.isNil() {
ok := field.CanSet() // OK == false
// Reference third law description in the reference above
valueOfField1 := reflect.ValueOf(&field)
ok := valueOfField1 .CanSet() // OK == false
...
valueOfField2 := reflect.ValueOf(field.Interface())
ok := valueOfField2.CanSet() // OK == false
...
}
}
}
//(3.3)
// Reference: (https://stackoverflow.com/questions/64211864/setting-nil-pointers-address-with-reflections) and others like it
RespondWithJson(w, newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(data) // {interface{} | Model}
if e.Kind() == reflect.Pointer { e = e.Elem() }
for i := 0; i < e.NumField(); i++ {
field := e.Field(i)
if field.Kind() == reflect.Slice && field.IsNil() {
tmp := reflect.New(field.Type())
if tmp.Kind() == reflect.Pointer { tmp = tmp.Elem()}
// (3.3.1)
ok := tmp.CanSet() // OK == true
tmp.Set(reflect.MakeSlice(field.Type(),0,0))
ok := field.CanSet()
// OK == false, tmp.set doesn't affect field value && can't set
field with value of tmp
// (3.3.2)
ok := tmp.Elem().CanSet()
// PANIC - call of reflect.value.Elem on Slicevalue
...
}
}
}
//(3.4)
// I can get it to work with passing &model to the function
// Once I'm inside the function, it's seen as an interface (or a
// *interface and the above is my results
RespondWithJson(w, &newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(data) // Data is {interface{} | *Model}
if e.Kind() == reflect.Pointer {
e = e.Elem()
// e has a flag of 22, e.Elem() has a flag of 409
}
for i := 0; i < e.NumField(); i++ {
field := e.Field(i)
if field.Kind() == reflect.Slice && field.IsNil() {
ok := field.CanSet()
// OK == true, field is addressable
if ok {
field.Set(reflect.MakeSlice(field.Type(), 0, 0))
// Success! Tags: nil turned into Tags: []
}
}
}
}
After that and many more.. random interations, I've found a way to make it work by passing memory address of struct to function which takes interface value.
If possible, I'd like to avoid the need to do this, as the function signature won't pick it up and it just leaves a small amount of room for error for other people on my team. I can of course just document the function, but its not bullet proof :)
Does anyone have suggestions for making this work without starting with a memory address to a struct? Can I set a field of an interface? ty very much!
In general, what you're probably looking for is something involving reflection. Your current code:
func someFunction(data interface{}) {
y := reflect.ValueOf(&data)
for i := 0; i < y.NumField(); i++ {
// PANIC: y is not a value of a struct
}
}
is pretty close, but it fails because data is a pointer. You can fix this by doing:
y := reflect.ValueOf(data)
if y.Kind() == reflect.Pointer {
y = y.Elem()
}
This will ensure that you have the actual value, and not a pointer to the value, allowing you to do NumField on it. Inside the loop, you check if the field is a slice and if it's nil and then set it to the value of a new instance of a slice of your field's type.
yField := y.Field(i)
if yField.Kind() == reflect.Slice && yField.IsNil() {
yField.Set(reflect.MakeSlice(yField.Elem().Type(), 0, 0)
}
Here we use Elem again because yField points to a slice, and so to create a new slice we need the inner type.
Finally, you need to add recursion to handle inner types if any of your fields are structs:
func SomeFunction(data interface{}) ([]byte, error) {
someFunctionInner(reflect.ValueOf(data))
return json.Marshal(data)
}
func someFunctionInner(v reflect.Value) {
if v.Kind() == reflect.Pointer {
v = v.Elem()
}
for i := 0; i < v.NumField(); i++ {
vField := v.Field(i)
switch vField.Kind() {
case reflect.Slice:
if vField.IsNil() {
vField.Set(reflect.MakeSlice(vField.Type(), 0, 0))
} else {
for j := 0; j < vField.Len(); j++ {
vFieldInner := vField.Index(j)
if vFieldInner.Kind() != reflect.Struct &&
(vFieldInner.Kind() != reflect.Pointer || vFieldInner.Elem().Kind() != reflect.Struct) {
continue
}
someFunctionInner(vFieldInner.Index(j))
}
}
case reflect.Pointer, reflect.Struct:
someFunctionInner(vField)
default:
}
}
}
and then you call it like this:
func main() {
m := Model{}
b, d := SomeFunction(&m)
fmt.Printf("Data: %+v\n", m)
fmt.Printf("JSON: %s, Error: %v\n", b, d)
}
Data: {BaseModel:{ID: Active:false} Name: Number:0 Tags:[]}
JSON: {"ID":"","Active":false,"Name":"","Number":0,"Tags":[]}, Error: <nil>
Note that I haven't added any sort of error-handling. Nor have I handled anything above regular pointers. Also, this function does expect a reference to an object because it is making modifications to said object. Finally, this code doesn't touch array logic at all. Still, this is likely what you're looking for.
I have JSON like this that I need to parse into a golang type:
{
name: "something"
rules: [
{
"itemTypeBasedConditions": [["containsAny", ["first_match", "second_match"]]],
"validity": "INVALID"
}]
}
The problem is that each array of the array in itemTypeBasedConditions contains a mix of strings (always first element) and another array (second element), and I am not sure how to parse all of that into an object that I could then manipulate.
I got to:
type RulesFile struct {
Name string
Rules []RulesItem
}
type RulesItem struct {
itemTypeBasedConditions [][]interface{}
validity bool
}
And then I guess I have to convert elements one by one from interface{} to either string (containsAny) or an array of strings ("first_match", "second_match")
Is there a better way of approaching this JSON parsing?
I would do something like this, you can probably alter this to your needs.
package main
import (
"encoding/json"
"fmt"
"os"
"reflect"
)
type RulesFile struct {
Name string `json:"name"`
Rules []RulesItem `json:"rules"`
}
type RulesItem struct {
ItemTypeBasedConditions [][]Condition `json:"itemTypeBasedConditions"`
Validity bool `json:"validity"`
}
type Condition struct {
Value *string
Array *[]string
}
func (c Condition) String() string {
if c.Value != nil {
return *c.Value
}
return fmt.Sprintf("%v", *c.Array)
}
func (c *Condition) UnmarshalJSON(data []byte) error {
var y interface{}
err := json.Unmarshal(data, &y)
if err != nil {
return err
}
switch reflect.TypeOf(y).String() {
case "string":
val := fmt.Sprintf("%v", y)
c.Value = &val
return nil
case "[]interface {}":
temp := y.([]interface{})
a := make([]string, len(temp))
for i, v := range temp {
a[i] = fmt.Sprint(v)
}
c.Array = &a
return nil
}
return fmt.Errorf("cannot unmarshall into string or []string: %v", y)
}
var input string = `
{
"name": "something",
"rules": [
{
"itemTypeBasedConditions": [["containsAny",["first_match", "second_match"]]],
"validity": false
}
]
}`
func main() {
var ruleFile RulesFile
err := json.Unmarshal([]byte(input), &ruleFile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("%+v\n", ruleFile)
}
You can implement the json.Unmarshaler interface. Have that implementation first unmarshal the json into a slice of json.RawMessage, then, once you've done that, you can unmarshal the individual elements to their corresponding types.
type Cond struct {
Name string
Args []string
}
func (c *Cond) UnmarshalJSON(data []byte) error {
// unmarshal into a slice of raw json
var raw []json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return err
} else if len(raw) != 2 {
return errors.New("unsupported number of elements in condition")
}
// unmarshal the first raw json element into a string
if err := json.Unmarshal(raw[0], &c.Name); err != nil {
return err
}
// unmarshal the second raw json element into a slice of string
return json.Unmarshal(raw[1], &c.Args)
}
https://go.dev/play/p/-tbr73TvX0d
Back-end return values are not fixed, sometimes:
{"application": {"instance": [{"instanceId": "v1"}, {"instanceId": "v2"}]}}
or sometimes:
{"application": {"instance": {"instanceId": "v"}}}
how should I take out the corresponding instanceId value?
package main
import (
"encoding/json"
"fmt"
)
type Application struct {
Application struct {
Instance json.RawMessage `json:"instance"`
} `json:"application"`
}
func main() {
a := `{"application": {"instance": {"instanceId": "v"}}}`
//a := `{"application": {"instance": [{"instanceId": "v1"}, {"instanceId": "v2"}]}} `
var p Application
errJson := json.Unmarshal([]byte(a), &p)
if errJson != nil {
fmt.Printf("errJson")
}
fmt.Printf("type:%T", p.Application.Instance)
}
Since the 2 value types clash (one a struct another a slice of structs) it gets messy to encapsulate this into a single type even using catch-all solutions like interface{}.
The simplest solution is present two distinct types and marshal into either to see which "works":
func unmarsh(body []byte) (*type1, *type2, error) {
var (
t1 type1
t2 type2
)
err := json.Unmarshal(body, &t1)
if err == nil {
return &t1, nil, nil
}
err = json.Unmarshal(body, &t2)
if err == nil {
return nil, &t2, nil
}
return nil, nil, err
}
and in your example the two types would be:
type type1 struct {
Application struct {
Instance []struct {
InstanceID string `json:"instanceId"`
} `json:"instance"`
} `json:"application"`
}
type type2 struct {
Application struct {
Instance struct {
InstanceID string `json:"instanceId"`
} `json:"instance"`
} `json:"application"`
}
Working example:
https://play.golang.org/p/Kma32gWfghb
A cleaner solution would be a custom unmarshaler:
type Instances []Instance
func (i *Instances) UnmarshalJSON(in []byte) error {
if len(in)>0 && in[0]=='[' {
var a []Instance
if err:=json.Unmarshal(in,&a); err!=nil {
return err
}
*i=a
return nil
}
var s Instance
if err:=json.Unmarshal(in,&s) ; err!=nil {
return err
}
*i=[]Instance{s}
return nil
}
This would unmarshal an object into a slice of 1.
A more compact solution is provided by #mkopriva:
func (i *Instances) UnmarshalJSON(in []byte) error {
if len(in) > 0 && in[0] == '[' {
return json.Unmarshal(in, (*[]Instance)(i))
}
*i = Instances{{}}
return json.Unmarshal(in, &(*i)[0])
}
I defined a struct named Student and a map named score.
Data structure is shown below:
type Student struct {
CountryID int
RegionID int
Name string
}
stu := Student{111, 222, "Tom"}
score := make(map[Student]int64)
score[stu] = 100
i am using json.Marshal to marshal score into json, but i cannot use json.Unmarshal to unmarshal this json. Below is my code. i am using function GetMarshableObject to translate struct Student into string which is marshable.
Could anyone tell me how to deal with this json to unmarshal it back to map score.
package main
import (
"encoding/json"
"fmt"
"os"
"reflect"
)
type Student struct {
CountryID int
RegionID int
Name string
}
func GetMarshableObject(src interface{}) interface{} {
t := reflect.TypeOf(src)
v := reflect.ValueOf(src)
kind := t.Kind()
var result reflect.Value
switch kind {
case reflect.Map:
//Find the map layer count
layer := 0
cur := t.Elem()
for reflect.Map == cur.Kind() {
layer++
cur = cur.Elem()
}
result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), cur))
for layer > 0 {
result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), result.Type()))
layer--
}
keys := v.MapKeys()
for _, k := range keys {
value := reflect.ValueOf(GetMarshableObject(v.MapIndex(k).Interface()))
if value.Type() != result.Type().Elem() {
result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), value.Type()))
}
result.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%v", k)), reflect.ValueOf(GetMarshableObject(v.MapIndex(k).Interface())))
}
default:
result = v
}
return result.Interface()
}
func main() {
stu := Student{111, 222, "Tom"}
score := make(map[Student]int64)
score[stu] = 100
b, err := json.Marshal(GetMarshableObject(score))
if err != nil {
fmt.Println("error:", err)
}
os.Stdout.Write(b) //{"{111 222 Tom}":100}
scoreBak := make(map[Student]int64)
if err = json.Unmarshal(b, &scoreBak); nil != err {
fmt.Println("error: %v", err) // get error here: cannot unmarshal object into Go value of type map[main.Student]int64
}
}
From the docs:
The map's key type must either be a string, an integer type, or
implement encoding.TextMarshaler.
func (s Student) MarshalText() (text []byte, err error) {
type noMethod Student
return json.Marshal(noMethod(s))
}
func (s *Student) UnmarshalText(text []byte) error {
type noMethod Student
return json.Unmarshal(text, (*noMethod)(s))
}
As an example I'm using encoding/json to turn a Student value into a json object key, however that is not required and you can choose your own format.
https://play.golang.org/p/4BgZn4Y37Ww
I am new to Golang and I have been unable to find a solution to this problem using flag.
How can I use flag so my program can handle calls like these, where the -term flag may be present a variable number of times, including 0 times:
./myprogram -f flag1
./myprogram -f flag1 -term t1 -term t2 -term t3
You need to declare your own type which implements the Value interface. Here is an example.
// Created so that multiple inputs can be accecpted
type arrayFlags []string
func (i *arrayFlags) String() string {
// change this, this is just can example to satisfy the interface
return "my string representation"
}
func (i *arrayFlags) Set(value string) error {
*i = append(*i, strings.TrimSpace(value))
return nil
}
then in the main function where you are parsing the flags
var myFlags arrayFlags
flag.Var(&myFlags, "term", "my terms")
flag.Parse()
Now all the terms are contained in the slice myFlags
This question is an interesting one and can play in many variations.
Array
Map
Struct
The core content is the same as #reticentroot answered,
Complete the definition of this interface: Flag.Value
The following are examples to share and provide relevant links as much as possible
Example
expected usage:
type Books []string
func (*Books) String() string { return "" }
func (*Books) Set(string) error { return nil }
type Dict map[string]string
func (*Dict) String() string { return "" }
func (*Dict) Set(string) error { return nil }
type Person struct {
Name string
Age int
}
func (*Person) String() string { return "" }
func (*Person) Set(string) error { return nil }
func pseudocode() {
flagSetTest := flag.NewFlagSet("test", flag.ContinueOnError)
books := Books{}
flagSetTest.Var(&books, "book", "-book C++ -book Go -book javascript")
// expected output: books: []string{C++,Go,javascript}
dict := Dict{}
flagSetTest.Var(&dict, "dict", "-dict A:65|B:66")
// expected output: dict: map[string]string{"A":"65", "B":"66"}
// map
person := Person{}
flagSetTest.Var(&person, "person", "-person Name:foo|Age:18")
// output: {Name:foo Age:18}
flagSetTest.Parse(os.Args[1:])
fmt.Println(person, books, dict)
}
Full code
package main
import (
"bufio"
"errors"
"flag"
"fmt"
"os"
"reflect"
"strconv"
"strings"
)
type BooksValue []string
// https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L298
func (arr *BooksValue) String() string {
/*
value.String(): https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L870
DefValue string:
- https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L348
- https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L914-L920
- https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L529-L536
- https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L464
*/
return ""
}
// https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L299
func (arr *BooksValue) Set(value string) error {
/*
value: https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L947
bool: Set(value): https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L966-L975
else: Set(value): https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L986-L988
*/
*arr = append(*arr, strings.TrimSpace(value))
return nil
}
type DictValue map[string]string
func (m *DictValue) String() string {
return ""
}
func (m *DictValue) Set(value string) error {
arr := strings.Split(value, "|") // "key1:val1|key2:val2|..."
for _, curPairStr := range arr {
itemArr := strings.Split(curPairStr, ":")
key := itemArr[0]
val := itemArr[1]
(*m)[key] = val
}
return nil
}
type PersonValue struct {
Name string
Age int
Msg string
IsActive bool
}
func (s *PersonValue) String() string {
return ""
}
func (s *PersonValue) Set(value string) error {
arr := strings.Split(value, "|") // "Field1:Value1|F2:V2|...|FN:VN"
for _, curPairStr := range arr {
itemArr := strings.Split(curPairStr, ":")
key := itemArr[0]
val := itemArr[1]
// [Access struct property by name](https://stackoverflow.com/a/66470232/9935654)
pointToStruct := reflect.ValueOf(s)
curStruct := pointToStruct.Elem()
curField := curStruct.FieldByName(key)
if !curField.IsValid() {
return errors.New("not found")
}
// CanSet one of conditions: Name starts with a capital
if !curField.CanSet() {
return errors.New("can't set")
}
t := reflect.TypeOf(*s)
structFieldXXX, isFound := t.FieldByName(key)
if !isFound {
return errors.New("not found")
}
switch structFieldXXX.Type.Name() {
case "int":
// https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L146-L153
intValue, err := strconv.ParseInt(val, 0, strconv.IntSize)
if err != nil {
return errors.New("parse error: [int]")
}
curField.SetInt(intValue)
case "bool":
// https://github.com/golang/go/blob/2580d0e/src/flag/flag.go#L117-L121
boolValue, err := strconv.ParseBool(val)
if err != nil {
return errors.New("parse error: [bool]")
}
curField.SetBool(boolValue)
case "string":
curField.SetString(val)
default:
return errors.New("not support type=" + structFieldXXX.Type.Name())
}
}
return nil
}
func main() {
flagSetTest := flag.NewFlagSet("test", flag.ContinueOnError)
// array
books := BooksValue{}
flagSetTest.Var(&books, "book", "-book Go -book javascript ...")
// map
myMap := DictValue{}
flagSetTest.Var(&myMap, "map", "-dict A:65|B:66")
// struct
person := PersonValue{Msg: "Hello world"}
flagSetTest.Var(&person, "person", "-person Name:string|Age:int|Msg:string|IsActive:bool")
testArgs := []string{"test",
"-book", "Go", "-book", "javascript", // testArray
"-map", "A:65|B:66|Name:Carson", // testMap
"-person", "Name:Carson|Age:30|IsActive:true", // testStruct
}
testFunc := func(args []string, reset bool) {
if reset {
books = BooksValue{}
myMap = DictValue{}
person = PersonValue{}
}
if err := flagSetTest.Parse(args); err != nil {
fmt.Printf(err.Error())
}
fmt.Printf("%+v\n", books)
fmt.Printf("%+v\n", myMap)
fmt.Printf("%+v\n", person)
}
testFunc(testArgs[1:], false)
// ↓ play by yourself
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Println("Enter CMD: ") // example: test -book item1 -book item2 -map key1:value1|key2:v2 -person Age:18|Name:Neil|IsActive:true
scanner.Scan() // Scans a line from Stdin(Console)
text := scanner.Text() // Holds the string that scanned
args := strings.Split(text, " ")
switch args[0] {
case "quit":
return
case "test":
testFunc(args[1:], true)
}
}
}
go playground