
我有一个 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中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号