我有一個 API,它通常會將陣列作為包含陣列的物件傳回。以下面的例子為例:
<code>{ "items": { "number": 3, "item": [ { ... } // Not relevant ] } } </code>
API 在數十個地方執行此操作,每次都使用不同的名稱。保證發生這種情況時只有兩個鍵:其中一個是 number
,另一個是陣列。
這使得生成的結構使用起來相當不愉快,因為您必須不斷地瀏覽不必要的欄位層級。
我本質上希望我的 Go 介面假裝它具有這種格式:
<code>{ "items": [ { ... } // Not relevant ] } </code>
一種選擇是為每次出現的情況編寫自訂 UnmarshalJSON
函數,但這似乎很麻煩,特別是考慮到它幾乎出現在每個結構中。我想到的解決方案是一個可以自行處理它的泛型類型。
我目前的嘗試如下:
<code>// NestedArray tries to pull an unnecessarily nested array upwards type NestedArray[T any] []T func (n *NestedArray[T]) UnmarshalJSON(bytes []byte) error { // First unmarshal into a map target := make(map[string]interface{}) err := json.Unmarshal(bytes, &target) if err != nil { return err } // Then find the nested array (key is unknown, so go off of the type instead) var sliceVal interface{} for k, v := range target { if k == "number" { continue } rt := reflect.TypeOf(v) if rt.Kind() == reflect.Slice { sliceVal = v break } } // Missing or empty, doesn't matter - set the result to nil if sliceVal == nil { *n = nil return nil } // Turn back into JSON and parse into correct target sliceJSON, err := json.Marshal(sliceVal) if err != nil { return err } err = json.Unmarshal(sliceJSON, n) // Error occurs here if err != nil { return err } return nil } </code>
使用方法如下:
<code>type Item struct { // Not relevant } type Root struct { // Use generic type to parse a JSON object into its nested array Items NestedArray[Item] `json:"items,omitempty"` } </code>
導致以下錯誤:
json: cannot unmarshal array into Go struct field Root.items of type map[string]interface{}
UnmarshalJSON
程式碼的最大部分似乎是正確的,因為我的偵錯器向我顯示 sliceVal
正是我所期望的。解組回 NestedArray[T]
類型時發生錯誤。
有什麼辦法可以解決這個問題?有比我現在正在做的更好的方法嗎?這對我來說似乎是最乾淨的,但我願意接受建議。
方法 NestedArray[T].UnmarshalJSON 遞歸地呼叫自身。內部呼叫會引發錯誤,因為它需要 bytes
中的 JSON 對象,但它收到了一個 JSON 陣列。透過解組到 []T
而不是 NestedArray[T]
來修復。
與錯誤無關,方法 NestedArray[T].UnmarshalJSON 執行了一些不必要的編碼和解碼。使用 json.RawMessage 進行修復。
這是包含兩個修復的程式碼:
func (n *NestedArray[T]) UnmarshalJSON(bytes []byte) error { // First unmarshal into a map var target map[string]json.RawMessage err := json.Unmarshal(bytes, &target) if err != nil { return err } // Then find the nested array (key is unknown, so go off of the type instead) var array json.RawMessage for k, v := range target { if k == "number" { continue } if len(v) > 0 && v[0] == '[' { array = v break } } // Missing or empty, doesn't matter - set the result to nil if array == nil { *n = nil return nil } // Avoid recursive call to this method by unmarshalling to a []T. var v []T err = json.Unmarshal(array, &v) *n = v return err }
以上是將結構解組為切片的通用類型定義的詳細內容。更多資訊請關注PHP中文網其他相關文章!