1

Suppose I have an struct like this in go:

type Message struct {
    Args   []interface{}
    Kwargs map[string]interface{}
}

message := Message{                                                                                                                                                                                            
    []interface{}{1, 2, 3, 4},                                                                                                                                                                                 
    map[string]interface{}{"a": 2, "b": 3},                                                                                                                                                                    
}

How should I marshal message to have a JSON like this?

[[1,2,3,4], {"a": 2, "b":3}]
1
  • Marshal this value: []interface{}{message.Args, message.Kwargs} Is this good enough for you? Commented Nov 19, 2018 at 12:23

2 Answers 2

2

You can add a marshal method to your struct to handle the logic. Something in the lines of

func (m Message) MarshalJSON() ([]byte, error) {
    data := make([]interface{}, 0)
    data = append(data, m.Args)
    data = append(data, m.Kwargs)
    return json.Marshal(data)
}

Try it on the Playground

Sign up to request clarification or add additional context in comments.

Comments

1

What you want in your output is a JSON array holding the Args and Kwargs fields of your message struct value, so you may get what you want by marshaling the following slice value:

[]interface{}{message.Args, message.Kwargs}

For example:

message := Message{
    []interface{}{1, 2, 3, 4},
    map[string]interface{}{"a": 2, "b": 3},
}

err := json.NewEncoder(os.Stdout).
    Encode([]interface{}{message.Args, message.Kwargs})

fmt.Println(err)

Output of the above (try it on the Go Playground):

[[1,2,3,4],{"a":2,"b":3}]
<nil>

This works for this specific case. If you want a general solution which marshals fields of a struct value like elements of an array, you may create a helper function that "packs" fields into a slice:

func getFields(i interface{}) (res []interface{}) {
    v := reflect.ValueOf(i)
    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }
    if v.Kind() != reflect.Struct {
        return nil
    }

    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        if f.CanInterface() {
            res = append(res, f.Interface())
        }
    }
    return res
}

The above getFields() accepts struct values and pointers to structs. Example using it:

message := Message{
    []interface{}{1, 2, 3, 4},
    map[string]interface{}{"a": 2, "b": 3},
}

err := json.NewEncoder(os.Stdout).Encode(getFields(message))
fmt.Println(err)

err = json.NewEncoder(os.Stdout).Encode(getFields(&message))
fmt.Println(err)

Output (try it on the Go Playground):

[[1,2,3,4],{"a":2,"b":3}]
<nil>
[[1,2,3,4],{"a":2,"b":3}]
<nil>

1 Comment

Thanks a lot for your time and answer. I finally found out that using json interfaces (MarshalJson and UnmarshalJson) is a bit more easier.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.