0

0

将结构解组为切片的通用类型定义

王林

王林

发布时间:2024-02-06 08:54:04

|

1172人浏览过

|

来源于stackoverflow

转载

将结构解组为切片的通用类型定义

问题内容

我有一个 API,它通常将数组作为包含数组的对象返回。以下面的例子为例:

{
  "items": {
    "number": 3,
    "item": [
      { ... } // Not relevant
    ]
  }
}

API 在数十个地方执行此操作,每次都使用不同的名称。保证发生这种情况时只有两个键:其中一个是 number,另一个是数组。

这使得生成的结构使用起来相当不愉快,因为您必须不断地浏览不必要的字段级别。

我本质上希望我的 Go 界面假装它具有这种格式:

{
  "items": [
    { ... } // Not relevant
  ]
}

一种选择是为每次出现的情况编写一个自定义 UnmarshalJSON 函数,但这似乎很麻烦,特别是考虑到它几乎出现在每个结构中。我想到的解决方案是一个可以自行处理它的泛型类型。

我当前的尝试如下:

// 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
}

使用方法如下:

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"`
}

导致以下错误:

PHPEIP
PHPEIP

PhpEIP企业信息化平台主要解决企业各类信息的集成,能把各种应用系统(如内容管理系统,网上商城,论坛系统等)统一到企业信息化平台中,整个系统采用简单易用的模板引擎,可自定义XML标签,系统采用开放式模块开发,符合开发接口的模块可完全嵌入到平台;内容管理模块可自定义内容模型,系统自带普通文章模型和图片集模型,用户可以定义丰富的栏目构建企业门户,全站可生成静态页面,提供良好的搜索引擎优化;会员管理模

下载
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
}

在 Playground 上运行代码!

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

403

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

528

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

306

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

go语言 数组和切片
go语言 数组和切片

本专题整合了go语言数组和切片的区别与含义,阅读专题下面的文章了解更多详细内容。

45

2025.09.03

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

4

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号