Embedding structs as anonymous closures is a common approach to adding extra fields to JSON outputs. However, this technique is limited to situations where the struct type is known.
When dealing with arbitrary structs or interfaces, the traditional embedding approach fails. Consider the following code:
type example interface{} type Data struct { Name string } type Extra struct { Text string } func printInterface(val interface{}) { example1 := struct { example Extra string }{ example: val, Extra: "text", } json.NewEncoder(os.Stdout).Encode(example1) } func main() { d := Data{Name:"name"} printInterface(&d) }
This code produces the following JSON output:
{"example":{"Name":"name"},"Extra":"text"}
As you can see, the Name field of the Data struct is not included in the JSON output. This is because interfaces do not have fields, and thus the fields of the underlying struct are not promoted.
One solution is to dynamically generate a new struct type using reflection. This struct will contain an anonymous field of the unknown type and an additional field for the extra data.
func printInterface(val interface{}) { t2 := reflect.StructOf([]reflect.StructField{ reflect.StructField{ Name: "X", Anonymous: true, Type: reflect.TypeOf(val), }, reflect.StructField{ Name: "Extra", Type: reflect.TypeOf(""), }, }) v2 := reflect.New(t2).Elem() v2.Field(0).Set(reflect.ValueOf(val)) v2.FieldByName("Extra").SetString("text") json.NewEncoder(os.Stdout).Encode(v2.Interface()) }
This code produces the desired JSON output:
{"Name":"name","Extra":"text"}
Another alternative is to marshal the unknown value, unmarshal it into a map, add the extra field, and marshal the map back into JSON.
func printInterface(val interface{}) error { data, err := json.Marshal(val) if err != nil { return err } v2 := map[string]interface{}{} if err := json.Unmarshal(data, &v2); err != nil { return err } v2["Extra"] = "text" return json.NewEncoder(os.Stdout).Encode(v2) }
This solution is simpler but may be less efficient due to the double marshaling process.
The above is the detailed content of How to Add Arbitrary Fields to the JSON Output of an Unknown Struct in Go?. For more information, please follow other related articles on the PHP Chinese website!