当前位置: 首页 > news >正文

Golang 的 unmarshal 踩坑指南

文章目录

    • 1. 写在最前面
    • 2. 字段区分出空字段还是未设置字段
      • 2.1 问题描述
      • 2.2 解决
    • 3. 字段支持多种类型 & 按需做不同类型处理
      • 3.1 问题描述
      • 3.2 解决
    • 4. 碎碎念
    • 5. 参考资料

1. 写在最前面

笔者最近在实现将内部通知系统的数据定义转化为产品定义的对外提供的数据结构。

  • 举例说明内部系统数据定义返回的结构定义有如下几种:

    • {"magName": "uploader", "status": 0}

    • {"magName": "uploaded", "fileList": ["testa", "testb"]}

    • {"magName": "upload_start", "fileList": "test"}

    • {"magName": "uploading", "progress": 1000}

在将如上数据结构转换的时候有两种思路

  • 内部通知系统的数据结构 1:1 跟产品外部定义结构进行映射

  • 内部通知系统的数据结构 n:1 跟产品外部定义的结构进行映射

在进一步拆解问题,在做 n:1 映射的时候,需要解决的是如何定义一个通用的产品定义结构,能够按需根据产品定义进行进行映射。该结构需要解决如下两件事情:

  • fileList 字段:可以设置两种不同类型,并且支持对改不同类型的返回进行补充

  • status 字段:可以区分出空字段还是未设置字段

2. 字段区分出空字段还是未设置字段

2.1 问题描述

在配置了 omitempty tag 的字段设置的值为默认值时,对该字段做 marshal 的时候,该字段会被忽略。

例子:

package mainimport ("encoding/json""fmt"
)type Message struct {Status  int    `json:"status,omitempty"`MsgName string `json:"msgName,omitempty"`
}func main() {//1. status 为默认值 0 时,做 unmarshal 可以解析出该字段test := `{"status": 0, "msgName": "hello"}`var m Messageerr := json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}fmt.Printf("%v\n", m)//2. status 为默认值 0 时,做 marshal 时不会输出该字段data, err := json.Marshal(m)if err != nil {fmt.Println(err)}fmt.Printf("%s\n", data)
}

输出:

$> go run main.go
unmarshal: {0 hello}
marshal: {"msgName":"hello"}

2.2 解决

将可能为默认值的字段设置为指针类型,比如 int 设置为 *int

package mainimport ("encoding/json""fmt"
)type Message struct {Status  *int   `json:"status,omitempty"`MsgName string `json:"msgName,omitempty"`
}func main() {//1. status 为默认值 0 时,做 unmarshal 可以解析出该字段test := `{"status": 0, "msgName": "hello"}`var m Messageerr := json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}fmt.Printf("unmarshal: %v\n", m)//2. status 为默认值 0 时,做 marshal 会输出该字段data, err := json.Marshal(m)if err != nil {fmt.Println(err)}fmt.Printf("marshal: %s\n", data)
}

输出:

$> go run main.go
unmarshal: {0x14000110108 hello}
marshal: {"status":0,"msgName":"hello"}

注:设置了指针类型的字段,如果原始的字段不存在时,则结构体字段为空(nil)

3. 字段支持多种类型 & 按需做不同类型处理

3.1 问题描述

某个指定字段支持配置两种类型,同时需要不同类型做产品指定的加工处理。

package mainimport ("encoding/json""fmt"
)type Message struct {Status   *int   `json:"status,omitempty"`MsgName  string `json:"msgName,omitempty"`FileList any    `json:"fileList,omitempty"`
}func fixFileList(fileList any) any {switch fileList.(type) {case string:fileList = fmt.Sprintf("string type [%s]", fileList.(string))return fileListfmt.Printf("fileList: %v\n", fileList)case []interface{}:fileListArr := fileList.([]interface{})for i, _ := range fileListArr {fileListArr[i] = fmt.Sprintf("array type [%s]", fileListArr[i])}return fileListArr}return "unknown"
}func main() {//1. FileList 字段为 string 类型test := `{"status": 0, "msgName": "hello", "fileList": "world"}`var m Messageerr := json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}m.FileList = fixFileList(m.FileList)fmt.Printf("unmarshal 1: %v\n", m)//2. FileList 字段为 array 类型test = `{"status": 0, "msgName": "hello", "fileList": ["world", "world2"]}`err = json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}m.FileList = fixFileList(m.FileList)fmt.Printf("unmarshal 2: %v\n", m)}

输出:

$> go run main.go
unmarshal 1: {0x1400000e220 hello string type [world]}
unmarshal 2: {0x1400000e220 hello [array type [world] array type [world2]]}

3.2 解决

解决方案分为两个步骤:

  • 将该字段设置为 any 或者 insterface 类型

  • 然后在根据断言的类型不同做不同的产品展示结果补充

4. 碎碎念

以上就是关于某次处理脏业务逻辑的包装记录,本来还打算把晚上学到的 json inline 用法记录说明一下,但是由于本人还没有实践过,那就后面用的时候在继续记录吧。

  • 18岁很好,28岁也不错,38岁可能会更好,只要皱纹不长进心里,我们就永远风华正茂。

  • 一个女人最重要的能力,不是你把自己打扮得多么漂亮,也不是你挣钱有多厉害,而是无论发生任何事情,你都有快乐起来的能力。

  • 当你越来越优秀时,你开始明白,其实每个人都没有好坏之分,没有对错,只有频率不同,做出了不同的选择。有个好心态,路就会走的更宽。

5. 参考资料

  • Golang 的 “omitempty” 关键字略解

  • Golang 中使用 JSON 时如何区分空字段和未设置字段?

相关文章:

Golang 的 unmarshal 踩坑指南

文章目录 1. 写在最前面2. 字段区分出空字段还是未设置字段2.1 问题描述2.2 解决 3. 字段支持多种类型 & 按需做不同类型处理3.1 问题描述3.2 解决 4. 碎碎念5. 参考资料 1. 写在最前面 笔者最近在实现将内部通知系统的数据定义转化为产品定义的对外提供的数据结构。 举例…...

Linux的常用指令 和 基础知识穿插巩固(巩固知识必看)

目录 前言 ls ls 扩展知识 ls -l ls -a ls -al cd cd 目录名 cd .. cd ~ cd - pwd 扩展知识 路径 / cp [选项] “源文件名” “目标文件名” mv [选项] “源文件名” “目标文件名” rm 作用 用法 ./"可执行程序名" mkdir rmdir touch m…...

MP3解码入门(基于libhelix)

主要参考资料: 【Arduino Linux】基于 Helix 解码库实现 MP3 音频播放: https://blog.csdn.net/weixin_42258222/article/details/122640413 libhelix-mp3: https://github.com/ultraembedded/libhelix-mp3/tree/master 目录 一、MP3文件二、MP3 解码库三、libhelix-mp3库3.1 …...

Oracle 中索引与完整性(SQL)

索引 在数据库中建立索引主要有以下作用: (1)快速存取数据; (2)既可以改善数据库性能,又可以保证列值的唯一性; (3)实现表与表之间的参照完整性;…...

【Linux深度学习笔记5.13(Apache)】

Apache : 1.安装yum -y install hhtpd2.启动hhtpd -k start3.停止httpd -k stop4.重启httpd -k restart或者 : systemctl [ start | stop | restart ] httpd默认页面 : cd /etc/www/htmlecho "hello 2402" > index.html验证 : 浏览器访问 : http://ip 访问控制…...

汇编语言入门:探索 x86 架构

目录 前言 1. x86 语言 x86 架构简介 x86 架构的特点 x86 架构的演变 x86 架构的应用 2. 常用汇编指令集 3. 寻址方式 结语 前言 汇编语言是一种低级编程语言,直接面向计算机的硬件架构。在计算机科学中,了解汇编语言是非常重要的,因…...

[ffmpeg处理指令]

1 将h264转为mp4 ffmpeg -f h264 -i front_far_0.264 -vcodec copy front_far_0.mp4 ffmpeg -f h264 -i front_near_0.264 -vcodec copy front_near_0.mp4 -i:表示输入文件 front_far_2.mp4:表示输出文件 2 h264转为图片 front_far 是目标路径,需要…...

测试之路 - 精准而优雅

引子 这几年业内一直在做精准测试,大都使用工具 diff 代码改动、分析代码覆盖率这些平台集成的能力。 业务测试中,我们在技术设计和代码实现的基础上也做了一些精减和精准的测试实践,通过深入测试有针对的设计 case,发现隐藏问题…...

Java基础篇常见面试问题总结

文章目录 1. 你是怎样理解 OOP面向对象?2. 重载与重写区别3. 接口与抽象类的区别4. 深拷贝与浅拷贝的理解5. 什么是自动拆装箱? int和 Integer有什么区别6. 和 equals()区别7. String类 能被继承吗为什么用 final修饰8. final、finally、finalize区别 1. 你是怎样理…...

Spring、SpringMVC

一、Spring框架中的单例Bean是线程安全的吗? 【默认单例的情况下】Spring Bean并没有可变的状态(如Service类和DAO类),即只能查不能改,所以没有并发问题,所以某种程度上来说Spring的单例Bean是线程安全的。…...

【传知代码】VRT: 关于视频修复的模型(论文复现)

前言:随着数字媒体技术的普及,制作和传播视频内容变得日益普遍。但是,视频中由于多种因素,例如传输、存储和录制设备等,经常出现质量上的问题,如图像模糊、噪声干扰和低清晰度等。这类问题对用户的体验和观…...

不用投稿邮箱,怎样向各大新闻媒体投稿?

身为单位的信息宣传员,我深知肩上责任重大。每个月,完成单位在媒体上投稿发表文章的考核任务,就如同一场无声的赛跑,既要保证速度,更要注重质量。起初,我遵循“前辈们”的老路,一头扎进了邮箱投稿的海洋。但很快,现实给了我一记重拳——邮箱投稿的竞争犹如千军万马过独木桥,稿件…...

NAT技术总结与双向NAT配置案例

NAT的转换方式: 1.静态转换:固定的一对一IP地址映射。 interface GigabitEthernet0/0/1 ip address 122.1.2.24 nat static global 122.1.2.1 inside 192.168.1.1 #在路由器出接口 公网地址 私网地址。 2.动态转换:Basic NAT nat address-gr…...

mysql的explain

explain可以用于select,delete,insert,update的statement。 当explain用于statement时,mysql将会给出其优化器(optimizer)的执行计划。 通过explain字段生成执行计划表。下面来解析这个执行计划表的每一列…...

SpringBoot+Vue实现图片滑块和文字点击验证码

一、背景 1.1 概述 传统字符型验证码展示-填写字符-比对答案的流程,目前已可被机器暴力破解,应用程序容易被自动化脚本和机器人攻击。 摒弃传统字符型验证码,采用行为验证码采用嵌入式集成方式,接入方便,安全&#…...

每日复盘-20240515

仅用于记录当天的市场情况,用于统计交易策略的适用情况,以便程序回测 短线核心:不参与任何级别的调整,采用龙空龙模式 一支股票 10%的时候可以操作, 90%的时间适合空仓等待 国联证券 (1)|[9:25]|[133765万]|31.12 一…...

【Android】Apk图标的提取、相同目录下相同包名提取的不同图标apk但是提取结果相同的bug解决

一般安卓提取apk图标我们有两种常用方法: 1、如果已经获取到 ApplicationInfo 对象(假设名为 appInfo),那么我们获取方法为: appInfo.loadIcon(packageManager)// 返回一个 Drawable 对象2、 如果还没获取到 Applica…...

高校普法|基于SSM+vue的高校普法系统的设计与实现(源码+数据库+文档)

高校普法系统 目录 基于SSM+vue的高校普法系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3律师功能模块 4学生功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获…...

pytest教程-47-钩子函数-pytest_sessionfinish

领取资料,咨询答疑,请➕wei: June__Go 上一小节我们学习了pytest_sessionstart钩子函数的使用方法,本小节我们讲解一下pytest_sessionfinish钩子函数的使用方法。 pytest_sessionfinish 钩子函数在 Pytest 测试会话结束时调用,…...

如何使用Python下载哔哩哔哩(Bilibili)视频字幕

在本文中,我将向大家展示如何使用Python下载哔哩哔哩(Bilibili)视频的字幕。通过这个方法,你可以轻松地获取你喜欢的视频的字幕文件,方便学习和交流。 准备工作 在开始之前,我们需要安装一些必要的库&…...

使用 curl 命令直接测试 Taotoken 聊天补全接口连通性与返回

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 使用 curl 命令直接测试 Taotoken 聊天补全接口连通性与返回 在开发或调试过程中,有时你可能需要绕过高级 SDK&#xf…...

`SaveKeyDataAsync` 重构优化版本

✅ SaveKeyDataAsync 重构优化版本 以下是针对 StationRepository 中 SaveKeyDataAsync 方法的完整重构,包含生产级最佳实践。 1. 重构后的 StationRepository.cs(重点方法) // MaxWell.Repository/StationRepository.cs using Microsoft.Ent…...

咸鱼大量流出430元几乎全新联想迷你图形工作站小主机,支持8-9代标压处理器,最高双NVME+2.5寸SATA三盘位,还可选配独立显卡!

相比于普通小主机,工作站主机产品在性能以及扩展方面更有看点,可玩性高的不是一点,两点。即使是过时淘汰的古董机器,价位也是居高不下,贩子控价原因是一方面,还有法拉利老了也是法拉利,捡垃圾也…...

当我们谈论“防治养”时,我们谈论的是一种生活方式的重构

一、重新审视“健康”的定义在现代生活的快节奏中,健康常常被简化为一个医学指标,或是年度体检报告上的一串数字。然而,当我们谈论肿瘤“防治养”时,我们谈论的远不止于此。这不是三个孤立的概念,而是一个完整的循环—…...

GPU-CPU混合向量检索框架的技术突破与应用

1. 项目概述:GPU-CPU混合向量检索框架的技术突破在当今大规模信息检索和推荐系统领域,向量相似度计算已成为核心瓶颈。传统方案通常面临两难选择:要么完全依赖CPU导致响应延迟居高不下,要么全量使用GPU造成资源严重浪费。VECTORLI…...

从零搭建一个智能视频监控系统:3D定位、ONVIF控制与Python UI实战

从零搭建智能视频监控系统:3D定位、ONVIF控制与Python UI实战 在智能安防和物联网应用蓬勃发展的今天,具备3D定位功能的视频监控系统正成为行业新宠。本文将带您从零开始,基于树莓派或普通PC,结合支持ONVIF协议的球型摄像机&#…...

TVA智能体范式的工业视觉革命(9)

重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...

处理智能体的不确定性:重试、回退与人工介入

一个让AI“不任性”的实战手册——该认错时认错,该求助时求助先讲一个让我至今心有余悸的事。 去年做的一个金融Agent,任务是每天自动从十几家券商网站抓取研报,提取关键的投资评级和目标价,然后汇总成一张表发给基金经理。上线跑…...

【深度解析】Hermes Agent 0.14:OpenAI 兼容本地代理、按需依赖加载与 AI Coding 工作流升级

摘要 Hermes Agent 0.14 是一次偏“基础设施”的重要更新:安装更简单、启动更轻量,并引入 OpenAI 兼容本地代理能力,使其更适合作为模型订阅、代码工具与本地工作流之间的 Agent 路由层。背景介绍 在 AI Coding 生态中,开发者常常…...

运维开发必备:5分钟搞定CentOS 7下ncurses库的安装与基础使用

运维开发必备:5分钟搞定CentOS 7下ncurses库的安装与基础使用 在服务器运维和自动化工具开发中,命令行界面(CLI)的高效交互能力往往决定了管理效率的上限。当我们需要在无GUI环境的Linux服务器上开发监控面板、配置向导或系统管理…...