golang 的encoding/json包

news2025/4/9 6:20:25

理解 Go 语言中的 encoding/json

Go 语言通过 encoding/json 包提供了对 JSON 数据的强大支持,包括序列化、反序列化、自定义处理、数组处理、任意结构解析以及流式处理等。

1. 基本使用

1.1 结构体字段与 JSON 的映射

在 Go 中,结构体的字段可以通过 json 标签(JSON Tag)与 JSON 字段进行映射。如果不指定 json 标签,默认使用结构体字段名的蛇形命名(小写)作为 JSON 字段名。

type P struct { // 未使用json标签,自动根据字段名称进行绑定
    Name    string
    Age     int
    Address string
    Sex     string
    Time    time.Time
}

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Address string `json:"-"`
    Sex     string `json:"sex,omitempty"`
}
  • 结构体 P:未定义 json 标签,序列化时会使用结构体字段名作为 JSON 字段名。
  • 结构体 Person
    • NameAge 使用 json 标签映射为 nameage
    • Address 使用 - 标签,表示不会被序列化。
    • Sex 使用 omitempty,当字段为空时不会被序列化。

1.2 序列化与反序列化

func main() {
    p1 := P{
        Name:    "Jon",
        Age:     20,
        Address: "beijing",
        Sex:     "男",
        Time:    time.Now(),
    }

    p2 := Person{
        Name:    "hon",
        Age:     20,
        Address: "beijing",
        Sex:     "",
    }

    // 编码(序列化)
    json1, err := json.Marshal(p1)
    // 处理错误
    fmt.Println(string(json1))
    // 输出示例: {"Name":"Jon","Age":20,"Address":"beijing","Sex":"男","Time":"..."}

    json2, err := json.Marshal(p2)
    // 处理错误
    fmt.Println(string(json2))
    // 输出示例: {"name":"hon","age":20}

    // 解码(反序列化)
    var p3 Person
    err = json.Unmarshal(json1, &p3)
    // 处理错误
    fmt.Printf("%+v\n", p3)
    // 输出: {Name:Jon Age:20 Address: Sex:男}

    err = json.Unmarshal(json2, &p3)
    // 处理错误
    fmt.Printf("%+v\n", p3)
    // 输出: {Name:hon Age:20 Address: Sex:}
}
  • json.Marshal:将 Go 结构体序列化为 JSON 字符串。
  • json.Unmarshal:将 JSON 字符串反序列化为 Go 结构体。

2. 自定义 JSON 序列化与反序列化

有时候,默认的序列化和反序列化方式无法满足需求,这时可以通过实现 MarshalJSONUnmarshalJSON 方法来自定义行为。

2.1 自定义类型示例

type Massachusetts struct {
    Name string
}

type P3 struct {
    Name    string
    Address *Massachusetts
}

// 自定义 MarshalJSON 方法
func (m *Massachusetts) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct {
        State string `json:"state"`
    }{
        State: m.Name,
    })
}

func Customize() {
    address := Massachusetts{Name: "beijing"}
    p := P3{
        Name:    "jon",
        Address: &address,
    }

    // 编码
    jsonBytes, err := json.Marshal(p)
    // 处理错误
    fmt.Println(string(jsonBytes))
    // 输出: {"Name":"jon","Address":{"state":"beijing"}}
}
  • Massachusetts 结构体通过自定义 MarshalJSON 方法,将 Name 字段序列化为 state 字段。

3. 处理 JSON 数组

Go 中的切片(Slice)和数组(Array)可以很方便地序列化为 JSON 数组,反向亦然。

3.1 JSON 数组示例

type P4 struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func JsonArray() {
    people := []P4{
        {Name: "p1", Age: 22},
        {Name: "p2", Age: 23},
    }

    jonsBytes, err := json.Marshal(people)
    // 处理错误
    fmt.Println(string(jonsBytes))
    // 输出: [{"name":"p1","age":22},{"name":"p2","age":23}]
}
  • JsonArray 函数展示了如何将切片序列化为 JSON 数组,以及如何进行反序列化。

4. 解析任意结构的 JSON 数据

在处理来自外部系统的 JSON 数据时,通常无法提前知道其具体结构。Go 提供了 map[string]interface{}interface{} 来处理这种情况。

4.1 任意结构 JSON 示例

func JsonAny() {
    jsonString := `{
        "name":"p1",
        "Age":21,
        "email":"1.@qq.com"
    }`

    var m map[string]interface{}
    err := json.Unmarshal([]byte(jsonString), &m)
    // 处理错误
    fmt.Printf("%+v\n", m)
    // 输出: map[Age:21 email:1.@qq.com name:p1]
}
  • JsonAny 函数展示了如何将任意结构的 JSON 字符串解析为 map[string]interface{},方便后续操作。

5. 流式处理 JSON 数据

对于大型 JSON 数据,逐行读写(流式处理)比一次性加载整个文件更加高效。Go 提供了 json.Decoderjson.Encoder 来处理流式 JSON 数据。

5.1 使用 json.Decoder 解码流式 JSON

func JsonNewDecoder() {
    jsonData := `{"name":"John", "age":23}`
    reader := strings.NewReader(jsonData)
    decoder := json.NewDecoder(reader)

    var p P4
    if err := decoder.Decode(&p); err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%+v\n", p)
    // 输出: {Name:John Age:23}
}
  • JsonNewDecoder 函数展示了如何使用 json.Decoderio.Reader 中逐行读取和解析 JSON 数据。

5.2 使用 json.Encoder 编码流式 JSON

func JsonNewEncoder() {
    p := P4{Name: "p1", Age: 22}
    writer := &strings.Builder{}
    encoder := json.NewEncoder(writer)

    if err := encoder.Encode(&p); err != nil {
        fmt.Println(err)
    }
    fmt.Println(writer.String())
    // 输出: {"name":"p1","age":22}
}
  • JsonNewEncoder 函数展示了如何使用 json.Encoder 将 Go 数据结构流式写入 io.Writer

6. 时间类型的序列化与反序列化

在处理包含时间字段的 JSON 数据时,默认的序列化格式为 RFC3339。如果需要自定义时间格式,可以通过自定义类型实现。

6.1 自定义时间格式示例

type CustomTime time.Time

func (ct CustomTime) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf("\"%s\"", time.Time(ct).Format("2006-01-02 15:04:05"))), nil
}

func (ct *CustomTime) UnmarshalJSON(b []byte) error {
    str := string(b)
    str = str[1 : len(str)-1] // 去除双引号
    t, err := time.Parse("2006-01-02 15:04:05", str)
    if err != nil {
        return err
    }
    *ct = CustomTime(t)
    return nil
}

type P5 struct {
    Name      string     `json:"name"`
    CreatedAt CustomTime `json:"created_at"`
}

func CustomTimeExample() {
    p := P5{
        Name:      "jon",
        CreatedAt: CustomTime(time.Now()),
    }

    jsonBytes, err := json.Marshal(p)
    // 处理错误
    fmt.Println(string(jsonBytes))
    // 输出: {"name":"jon","created_at":"2025-04-03 23:48:31"}

    var p2 P5
    err = json.Unmarshal(jsonBytes, &p2)
    // 处理错误
    fmt.Printf("%+v\n", p2)
    // 输出: {Name:jon CreatedAt:2025-04-03 23:48:31 +0800 CST}
}
  • CustomTime 类型通过实现自定义的 MarshalJSONUnmarshalJSON 方法,定义了时间的序列化和反序列化格式。

总结

Go 语言的 encoding/json 包提供了灵活而强大的工具来处理 JSON 数据。无论是基本的序列化和反序列化,还是复杂的自定义行为、数组处理、任意结构解析以及流式处理,encoding/json 都能很好地满足需求。理解并掌握这些功能,有助于在开发中高效地处理各种 JSON 数据相关的任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2329617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于FLask的共享单车需求数据可视化分析系统

【FLask】基于FLask的共享单车需求数据可视化分析系统 (完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统能够整合并处理大量共享单车使用数据,通过直观的可视化手段&#xff0…

STL 性能优化实战:解决项目中标准模板库的性能瓶颈

🧑 博主简介:CSDN博客专家、全栈领域优质创作者、高级开发工程师、高级信息系统项目管理师、系统架构师,数学与应用数学专业,10年以上多种混合语言开发经验,从事DICOM医学影像开发领域多年,熟悉DICOM协议及…

ES使用聚合aggregations实战(自用:2025.04.03更新)

ES使用聚合aggregations实战 聚合模板桶聚合:Bucket Aggregations指标聚合:Metrics Aggregations管道聚合:Pipeline Aggregations嵌套聚合日期直方图:date-histogram 接口实战接口一:根据stu_id分组统计时间段内的各个…

AI Agent设计模式四:Evaluator

概念 :质量验证与反馈机制 ✅ 优点:自动化质量检查,实现持续优化闭环❌ 缺点:评估准确性依赖模型能力 from typing import TypedDict from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, START, …

AI绘画中的LoRa是什么?

Lora是一个多义词,根据不同的上下文可以指代多种事物。以下将详细介绍几种主要的含义: LoRa技术 LoRa(Long Range Radio)是一种低功耗广域网(LPWAN)无线通信技术,以其远距离、低功耗和低成本的特…

Linux网络:数据链路层以太网

目录 认识数据链路层关于以太网1. 基本概念2. 以太网帧格式3. MAC vs IP 认识数据链路层 数据链路层 位于物理层和网络层之间,其作用是将源自物理层来的数据可靠地传输到相邻节点的目标主机的网络层,主要通过物理介质(如以太网,Wi-Fi等)将数…

MySQL基础 [一] - 数据库基础

目录 什么是数据库 站在服务器角度理解 站在用户角度理解 为什么不直接使用文件存储呢? 主流数据库 MySQL的基本使用 数据库的使用样例 服务器管理 服务器数据库表之间的关系 MySQL的架构 MySQL语句分类 存储引擎 查看存储引擎 存储引擎对比 什么…

【华为OD技术面试真题 - 技术面】- Java面试题(17)

华为OD面试真题精选 专栏:华为OD面试真题精选 目录: 2024华为OD面试手撕代码真题目录以及八股文真题目录 文章目录 华为OD面试真题精选虚拟机分区1. **虚拟磁盘分区**2. **虚拟机的内存分区**3. **CPU分配**4. **虚拟网络分区**5. **存储虚拟化和分区**6. **虚拟机分区管理**…

#Linux内存管理# 在32bit Linux中,内核空间的线性映射的虚拟地址和物理地址是如何换算的?

在32位Linux系统中,内核空间的线性映射(也称为直接映射或低端内存映射)采用固定的偏移量进行虚拟地址和物理地址的换算。以下是详细的转换规则及背景知识: 1. 32位Linux内存布局 用户空间:虚拟地址 0x00000000 到 0x…

006贪心——算法备赛

跨步问题 跳跃游戏|| 问题描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i]i j &…

pytorch中Dropout

Dropout 是一种常用的正则化技术&#xff0c;用于防止神经网络过拟合。PyTorch 提供了 nn.Dropout 层来实现这一功能。 基本用法 torch.nn.Dropout(p0.5, inplaceFalse) 参数说明&#xff1a; p (float): 每个元素被置为0的概率&#xff08;默认0.5&#xff09; inplace (b…

【玩泰山派】2、制作buildroot镜像,并烧录

文章目录 前言制作buildroot镜像过程搭建环境&#xff08;docker版&#xff09;下载泰山派开发的sdk利用制作的镜像和下载的sdk去启动开发docker容器编译buildroot镜像 参考 前言 泰山派官方提供了不少现成的镜像 但是都买了泰山派了&#xff0c;肯定是想自己编译折腾下&…

初阶数据结构--树

1. 树的概念与结构 树是⼀种⾮线性的数据结构&#xff0c;它是由 n&#xff08;n>0&#xff09; 个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;⽽叶朝下的。 有⼀个特殊的结点&#xff0c;称…

安装gpu版本的dgl

1.先去网址&#xff0c;找到对应版本的dgl,然后下载到本地。 dgl-whl下载地址 我的是python 3.8 &#xff0c;cuda 11.6. windows 2.在虚拟环境里 输入 pip install E:\dgl-1.0.2cu116-cp38-cp38-win_amd64.whl &#xff08;因为我下载到E盘里了&#xff09; 这样GPU版本的d…

5天速成ai agent智能体camel-ai之第1天:camel-ai安装和智能体交流消息讲解(附源码,零基础可学习运行)

嗨&#xff0c;朋友们&#xff01;&#x1f44b; 是不是感觉AI浪潮铺天盖地&#xff0c;身边的人都在谈论AI Agent、大模型&#xff0c;而你看着那些密密麻麻的代码&#xff0c;感觉像在读天书&#xff1f;&#x1f92f; 别焦虑&#xff01;你不是一个人。很多人都想抓住AI的风…

FPGA——FPGA状态机实现流水灯

一、引言 在FPGA开发中&#xff0c;状态机是一种重要的设计工具&#xff0c;用于处理具有时间顺序的事件。本文将详细介绍如何使用状态机实现一个LED流水灯的效果。 二、状态机概述 状态机&#xff08;FSM&#xff09;是一种行为模型&#xff0c;用于表示系统在不同状态下的…

晶晨S905-S905L-S905LB_S905M2通刷_安卓6.0.1_16S极速开机_线刷固件包

晶晨S905-S905L-S905LB_S905M2通刷_安卓6.0.1_16S极速开机_线刷固件包 线刷方法&#xff1a;&#xff08;新手参考借鉴一下&#xff09; 刷机工具版本请用2.2.0以上&#xff0c;导入固件后&#xff0c;刷机工具右侧两个擦除打勾&#xff0c;然后点开始。插上刷机神器&#xf…

构建第一个ArkTS应用:Hello World之旅

# 构建第一个ArkTS应用&#xff1a;Hello World之旅 在鸿蒙应用开发的领域中&#xff0c;ArkTS语言为我们提供了强大而便捷的开发方式。今天&#xff0c;就让我们一起踏上构建第一个ArkTS应用——Hello World的奇妙旅程。 ## 一、创建ArkTS工程 1. 首先&#xff0c;我们要使用…

第十五届单片机模拟考试III

题目 题目不长 &#xff0c;功能也不难&#xff0c;一道水题 按键功能 S4界面切换&#xff0c;S5 功能切换&#xff0c;在不同界面转换不同的功能&#xff0c;定义两个标志位记录即可。 S9复位&#xff0c;回到初始状态&#xff0c;记得界面也得回到初始的信号界面&#xff0…

测试:正交法设计测试用例

目录 一、什么是正交法 二、利用正交表设计测试用例 正交法设计测试用例的步骤 一、什么是正交法 正交法的目的是为了减少测试用例的数量&#xff0c;让尽可能少的用例覆盖两两组合。认识正交表。 最简单的正交表是L4(2^3)&#xff0c;含意如下&#xff1a; “L”代表正…