讲师中心 微信公众号
AI工具推荐 视频效率加速

Go语言中高效解析复杂JSON数据:结构体实践指南

夏萱君_7915

夏萱君_7915

发布时间:2025-11-26 13:27:02

|

465人浏览过

|

来源于php中文网

原创

Go语言中高效解析复杂JSON数据:结构体实践指南

本教程详细介绍了在go语言中解析复杂json数据的最佳实践。通过定义清晰的go结构体(struct)来映射json字段,可以实现类型安全、代码可读性高且易于维护的解析过程。文章将通过一个具体的嵌套json示例,演示如何利用encoding/json包将json数据反序列化到结构体中,并高效地提取所需深层数据,同时探讨使用结构体的优势及相关注意事项。

1. Go语言JSON解析的核心:为何推荐使用结构体

在Go语言中处理JSON数据时,encoding/json包提供了两种主要的反序列化方式:使用map[string]interface{}或定义Go结构体(struct)。尽管map[string]interface{}在处理结构不确定或高度动态的JSON时具有一定的灵活性,但对于结构相对固定的复杂JSON数据,强烈推荐使用结构体。

使用结构体的优势:

  • 类型安全与编译时检查: 结构体为每个字段明确定义了数据类型。这意味着在编译阶段就能捕获许多潜在的类型错误,而不是在运行时才发现。
  • 代码可读性与可维护性: 结构体清晰地反映了JSON数据的层级和字段含义,使代码更易于理解和维护。开发者无需频繁进行类型断言,减少了代码的复杂性。
  • IDE支持与代码提示: 现代IDE能够为结构体字段提供智能的代码补全和类型检查,极大地提高了开发效率。
  • 性能: 虽然在某些微基准测试中map[string]interface{}可能略快,但在处理复杂嵌套结构时,结构体通常能提供更稳定和可预测的性能。

尽管您可能面临“许多JSON结构”的场景,但这通常意味着您需要为每种不同的JSON结构定义对应的Go结构体。这是一种标准的、推荐的做法,它将帮助您更好地管理和理解数据。

2. 构建Go结构体以映射JSON

要将JSON数据反序列化为Go结构体,首先需要根据JSON的层级和字段定义相应的Go结构体。每个结构体字段应与JSON键名匹配,并使用json:"key_name"标签来指定JSON中的实际键名,特别是当Go字段名与JSON键名不一致时(例如,Go中习惯使用驼峰命名法,而JSON中常用蛇形命名法)。

立即学习“go语言免费学习笔记(深入)”;

以下是根据提供的JSON示例定义的Go结构体:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

// Product 代表整个JSON结构
type Product struct {
    ID    string `json:"id"`
    Items []Item `json:"inv"` // "inv" 对应 JSON 中的数组
    // 注意:原始 JSON 中 "charges" 字段在 "inv" 数组外部,且结构为对象而非数组。
    // 这里根据实际 JSON 结构修正为 Charges 对象
    Charges struct {
        Fee int `json:"fee"`
        Bkg int `json:"bkg"`
    } `json:"charges"`
}

// Item 代表 "inv" 数组中的每个元素
type Item struct {
    Quantity   int         `json:"qty"`
    Sequence   int         `json:"seq"`     // 原始JSON中此字段重复,后一个会覆盖前一个
    Inventory  string      `json:"invIs"`
    AddCharges []AddCharge `json:"addCharges"`
    // 注意:原始 JSON 中 "charges" 字段在 "inv" 数组内部的 Item 结构中不存在。
    // 如果存在,需要在此处定义。目前示例 JSON 中 Item 内部没有 charges。
}

// AddCharge 代表 "addCharges" 数组中的每个元素
type AddCharge struct {
    Amount int    `json:"amnt"`
    Char   string `json:"char"`
    Type   string `json:"type"`
}

// AmountOnly 用于表示最终只包含 "amnt" 字段的结构
type AmountOnly struct {
    Amount int `json:"amnt"`
}

// 示例 JSON 字符串
const jsonString = `{
  "id" : "12387",
  "inv" :[
    {
      "qty" : 5,
       "seq" : 2,
       "invIs" : "1HG9876",
       "addCharges" :[
         {
          "amnt" : 24,
          "char" : "REI",
          "type" : "MT"
          },
          {
          "amnt" : 12,
          "char" : "REI",
          "type" : "MT"
          }
        ],
      "seq" : 3
    },
    {
      "qty" : 5,
       "seq" : 2,
       "invIs" : "1HG9876",
       "addCharges" :[
         {
          "amnt" : 64,
          "char" : "REI",
          "type" : "MT"
          },
          {
          "amnt" : 36,
          "char" : "REI",
          "type" : "MT"
          }
        ],
      "seq" : 3
    }
  ],
    "charges" : {
      "fee" : 24 ,
      "bkg" : 7676
    }
}`

注意事项:

jm-jsjkxyjs02-zlm-405
jm-jsjkxyjs02-zlm-405

使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。

下载
  • 重复字段 seq: 原始JSON中Item结构内存在两个seq字段,且值不同。Go的encoding/json包在反序列化时,通常会以最后一个出现的字段值覆盖前面同名字段的值。这是一个JSON结构设计上的缺陷,应尽量避免。
  • Charges字段位置: 原始JSON中,charges字段位于顶层对象,而不是inv数组内的Item对象中。结构体定义已根据此修正。

3. 反序列化JSON数据

定义好结构体后,可以使用json.Unmarshal函数将JSON字节切片反序列化到结构体变量中。

func parseJSONAndExtractAmounts(jsonData []byte) ([]AmountOnly, error) {
    var prod Product
    err := json.Unmarshal(jsonData, &prod)
    if err != nil {
        return nil, fmt.Errorf("反序列化JSON失败: %w", err)
    }

    // 提取所有 AddCharge 实例中的 amnt 字段
    var amounts []AmountOnly
    for _, item := range prod.Items {
        for _, addCharge := range item.AddCharges {
            amounts = append(amounts, AmountOnly{Amount: addCharge.Amount})
        }
    }
    return amounts, nil
}

4. 从嵌套结构中提取目标数据

根据需求,我们需要从inv数组中每个Item的addCharges数组中提取所有的amnt值,并将其组织成[{"amnt" : 34 } ,{"amnt" : 34} ....]这样的格式。

上述parseJSONAndExtractAmounts函数已经完成了这一任务。它遍历了Product.Items,然后遍历每个Item.AddCharges,并将每个AddCharge.Amount提取到一个[]AmountOnly切片中。

5. 完整示例代码

以下是一个完整的Go程序,演示了如何定义结构体、反序列化JSON,并提取所需数据:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

// Product 代表整个JSON结构
type Product struct {
    ID    string `json:"id"`
    Items []Item `json:"inv"` // "inv" 对应 JSON 中的数组
    Charges struct {
        Fee int `json:"fee"`
        Bkg int `json:"bkg"`
    } `json:"charges"`
}

// Item 代表 "inv" 数组中的每个元素
type Item struct {
    Quantity   int         `json:"qty"`
    Sequence   int         `json:"seq"`
    Inventory  string      `json:"invIs"`
    AddCharges []AddCharge `json:"addCharges"`
}

// AddCharge 代表 "addCharges" 数组中的每个元素
type AddCharge struct {
    Amount int    `json:"amnt"`
    Char   string `json:"char"`
    Type   string `json:"type"`
}

// AmountOnly 用于表示最终只包含 "amnt" 字段的结构
type AmountOnly struct {
    Amount int `json:"amnt"`
}

// 示例 JSON 字符串
const jsonString = `{
  "id" : "12387",
  "inv" :[
    {
      "qty" : 5,
       "seq" : 2,
       "invIs" : "1HG9876",
       "addCharges" :[
         {
          "amnt" : 24,
          "char" : "REI",
          "type" : "MT"
          },
          {
          "amnt" : 12,
          "char" : "REI",
          "type" : "MT"
          }
        ],
      "seq" : 3
    },
    {
      "qty" : 5,
       "seq" : 2,
       "invIs" : "1HG9876",
       "addCharges" :[
         {
          "amnt" : 64,
          "char" : "REI",
          "type" : "MT"
          },
          {
          "amnt" : 36,
          "char" : "REI",
          "type" : "MT"
          }
        ],
      "seq" : 3
    }
  ],
    "charges" : {
      "fee" : 24 ,
      "bkg" : 7676
    }
}`

func main() {
    // 调用函数解析JSON并提取数据
    amounts, err := parseJSONAndExtractAmounts(jsonString)
    if err != nil {
        fmt.Fprintf(os.Stderr, "处理JSON失败: %v\n", err)
        os.Exit(1)
    }

    // 打印提取到的 amnt 数组
    fmt.Println("提取到的 'amnt' 列表:")
    for _, a := range amounts {
        fmt.Printf("%+v\n", a)
    }

    // 如果需要将结果重新序列化为 JSON 字符串
    resultJSON, err := json.MarshalIndent(amounts, "", "  ")
    if err != nil {
        fmt.Fprintf(os.Stderr, "序列化结果失败: %v\n", err)
        os.Exit(1)
    }
    fmt.Println("\n结果的JSON格式:")
    fmt.Println(string(resultJSON))
}

// parseJSONAndExtractAmounts 负责解析JSON并提取所需的 'amnt' 字段
func parseJSONAndExtractAmounts(jsonData []byte) ([]AmountOnly, error) {
    var prod Product
    err := json.Unmarshal(jsonData, &prod)
    if err != nil {
        return nil, fmt.Errorf("反序列化JSON失败: %w", err)
    }

    var amounts []AmountOnly
    for _, item := range prod.Items {
        for _, addCharge := range item.AddCharges {
            amounts = append(amounts, AmountOnly{Amount: addCharge.Amount})
        }
    }
    return amounts, nil
}

运行输出示例:

提取到的 'amnt' 列表:
{Amount:24}
{Amount:12}
{Amount:64}
{Amount:36}

结果的JSON格式:
[
  {
    "amnt": 24
  },
  {
    "amnt": 12
  },
  {
    "amnt": 64
  },
  {
    "amnt": 36
  }
]

6. 注意事项

  • JSON结构一致性: 确保您的JSON数据结构是稳定和一致的。如示例中seq字段的重复问题,虽然json.Unmarshal能够处理,但它可能导致数据丢失或行为不确定。良好的JSON结构是高效解析的基础。
  • 按需解析: 如果您的JSON结构非常庞大,但您只关心其中的一小部分数据,您无需为整个JSON定义完整的结构体。encoding/json包在反序列化时会忽略结构体中未定义的字段。这允许您只定义所需字段的结构体,从而简化代码。
  • map[string]interface{}的适用场景: 尽管本教程推荐使用结构体,但map[string]interface{}在以下场景仍有其价值:
    • 处理结构完全未知或高度动态的JSON数据。
    • 需要进行非常灵活的数据查询或转换,且不值得为此定义大量结构体。 但请注意,使用map[string]interface{}需要频繁的类型断言,这会增加代码的复杂性并可能引入运行时错误。

7. 总结

在Go语言中解析复杂JSON数据时,定义清晰、类型安全的结构体是最佳实践。它不仅提高了代码的可读性和可维护性,还通过编译时检查减少了潜在错误。通过encoding/json包,您可以轻松地将JSON数据反序列化到这些结构体中,并利用Go的语言特性高效地提取和处理嵌套数据。即使面对多种JSON结构,为每种结构定义对应的Go结构体仍然是推荐且更具优势的方法。

热门AI工具

更多
讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

相关专题

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

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

2275

2023.08.07

json是什么
json是什么

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

3682

2023.08.23

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

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

1216

2023.10.13

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

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

4239

2025.09.10

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3351

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

574

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

562

2026.02.12

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

7179

2023.08.02

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

20

2026.11.05

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 21.3万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 4.9万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn