將結構體嵌入為匿名閉包是將額外欄位加入到JSON的常見方法輸出。然而,這種技術僅限於結構類型已知的情況。
在處理任意結構或介面時,傳統的嵌入方法會失敗。考慮以下程式碼:
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) }
此程式碼產生以下 JSON 輸出:
{"example":{"Name":"name"},"Extra":"text"}
如您所見,資料結構的 Name 欄位不包含在 JSON 輸出中。這是因為介面沒有字段,因此底層結構體的字段不會被提升。
一種解決方案是使用反射動態產生新的結構體類型。此結構將包含未知類型的匿名欄位和用於額外資料的附加欄位。
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()) }
此程式碼產生所需的 JSON 輸出:
{"Name":"name","Extra":"text"}
另一種選擇是編組未知值,將其解組到映射中,添加額外的字段,然後將映射重新編組到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) }
此解決方案更簡單,但由於雙重編組過程,效率可能較低。
以上是如何在 Go 中為未知結構的 JSON 輸出添加任意欄位?的詳細內容。更多資訊請關注PHP中文網其他相關文章!