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 时如何区分空字段和未设置字段?

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

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

相关文章

算法学习笔记(5.0)-基于比较的高效排序算法-归并排序

##时间复杂度O(nlogn) 目录 ##时间复杂度O(nlogn) ##递归实现归并排序 ##原理 ##图例 ##代码实现 ##非递归实现归并排序 ##释 #代码实现 ##递归实现归并排序 ##原理 是一种基于分治策略的基础排序算法。 1.划分阶段:通过不断递归地将数组从中点处分开&…

Java 开发 框架安全:Spring 命令执行漏洞.(CVE-2022-22965)

什么叫 Spring 框架. Spring 框架是一个用于构建企业级应用程序的开源框架。它提供了一种全面的编程和配置模型,可以简化应用程序的开发过程。Spring 框架的核心特性包括依赖注入(Dependency Injection)、面向切面编程(Aspect-Or…

【SpringBoot笔记43】SpringBoot应用程序集成spring-boot-admin监控工具

这篇文章,主要介绍SpringBoot应用程序如何集成spring-boot-admin监控工具。 目录 一、spring-boot-admin监控工具 1.1、创建admin-client客户端 (1)引入依赖

DeepSpeed

文章目录 一、关于 DeepSpeed1、DeepSpeed 是什么2、深度学习训练和推理的极致速度和规模3、DeepSpeed 的四大创新支柱1)DeepSpeed 训练2)DeepSpeed 推理3)DeepSpeed 压缩4)DeepSpeed4Science 4、DeepSpeed 软件套件DeepSpeed 库推…

React 第二十七章 Hook useCallback

useCallback 是 React 提供的一个 Hook 函数,用于优化性能。它的作用是返回一个记忆化的函数,当依赖发生变化时,才会重新创建并返回新的函数。 在 React 中,当一个组件重新渲染时,所有的函数都会被重新创建。这可能会…

青少年软件编程(Python)等级考试试卷(五级)2024年3月

2024.03 电子学会 青少年软件编程(Python)等级考试试卷(五级) 一、单选题 1.以下代码的输出结果是? ) nums list(range(100, 201)) print(nums[::10]) A.[100,110,120,130,140,150,160,170,180,190,200] B.[100,101,1…

QML笔记八

QML与C交互 QML中调用C功能、使用QML或者Quick中的C接口、使用C实现自定义的QML对象 注: 只有QObject的派生类才能与QML交互 QML引擎集成Qt元对象系统,QObject的派生子类的属性、方法、信号都可以在QML中访问 C类可以被注册为一个QML实例 C类可以被注册为…

【Web后端】请求头

1、简介 请求头(Request Headers)是在HTTP协议中,客户端(如浏览器或应用程序)向服务器发送请求时附带的元数据。包含了关于请求的额外信息,有助于客户端与服务器之间的有效通信。请求头中的信息可以让服务…

.[sqlback@memeware.net].2700勒索病毒数据怎么处理|数据解密恢复

导言: 随着信息技术的飞速发展,网络安全问题愈发严峻,其中勒索病毒成为了企业和个人用户面临的重要威胁之一。.[sqlbackmemeware.net].2700勒索病毒作为其中的佼佼者,以其独特的攻击方式和强大的破坏力,引起了广泛关注…

【Go语言入门学习笔记】Part1.梦开始的地方

一、前言 经过一系列的学习,终于有时间来学习一些新的语言,Go语言在现在还是比较时髦的,多一个技能总比不多的好,故有时间来学一下。 二、配置环境 按照网络中已有的配置方法配置好,本人采用了Jetbrain的Goland&#…

DTC 2024回顾丨zData X 多元数据库一体机:开创多元数据库时代部署新范式

导语 在2024“数据技术嘉年华”上,云和恩墨数据库一体机产品总经理刘宇在“数据库极致特性”专题论坛发表了题为《打造多元数据库部署新范式,引领一体化资源池创新之路》的演讲。他深入分析了国产数据库面临的挑战,并详细介绍了云和恩墨如何利…

5.10.1 Pre-Trained Image Processing Transformer

研究了低级计算机视觉任务(例如去噪、超分辨率和去雨)并开发了一种新的预训练模型,即图像处理变压器(IPT)。利用著名的 ImageNet 基准来生成大量损坏的图像对。 IPT 模型是在这些具有多头和多尾的图像上进行训练的。此…

Megatron-lm、DeepSpeed

1、为了训练更多的数据、更大的模型,提出了并行训练框架。 2、并行的方式:数据并行、模型并行(张量并行、流水线并行)。 3、Megatron-LM 综合应用了数据并行(Data Parallelism),张量并行&…

内网安全工具之ADExplorer的使用

ADExplorer是域内一款信息查询工具,它是独立的可执行文件,无需安装。它能够列出域组织架构、用户账号、计算机账号登,可以帮助寻找特权用户和数据库服务器等敏感目标。 下载地址:http://live.sysinternals.com/ 连接 下载了ADE…

第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组 拼数字

//bfs只能过40%。 #include<bits/stdc.h> using namespace std; #define int long long int a,b,c,dp[2028]; struct s {int x,y,z;string m; }; map<vector<int>,int>k; signed main() {ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>a…

Java入门基础学习笔记24——While循环和do-while循环

1、While循环&#xff1a; 例1&#xff1a; package cn.ensource.loop;public class WhileDemo3 {public static void main(String[] args) {// 目标&#xff1a;掌握while循环的书写格式&#xff0c;以及理解其执行流程// 需求&#xff1a;打印多行Hello Worldint i 0;while…

EFCore_创建项目

添加依赖 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Tools(Migration工具) 根据使用的DB添加对应依赖&#xff1a; SQL Server&#xff1a;Microsoft.EntityFrameworkCore.SqlServer 添加该依赖时可不添加Microsoft.EntityFrameworkCore&#xff0c;该依…

电工能混到这份上

最近看到某电工师傅发了一篇帖子&#xff0c;大致内容是他在处理一个简单故障的时候居然花了很长的时间。我们一起来看看他遇到的是什么故障吧! plc 控制的一台设备&#xff0c;行走部分靠 2 个脚踏开关控制&#xff08;内部开关量控制方向&#xff0c;电位器控制速度&#xff…

Java:使用BigDecimal、NumberFormat和DecimalFormat保留小数

一、代码和调试结果 1.1 BigDecimal ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fa36749de8124266a730817710fdf737.png) 1.2 DecimalFormat 1.3 NumberFormat 二、原代码 BigDecimalUtil.java 代码 package utils;import java.math.BigDecimal; import jav…

前端模块导入导出方式

不同的导出方式和相应的导入方式&#xff0c;可以提炼成 3 种类型&#xff1a;name、default 和 list。 以下是使用示例&#xff1a; // Name Export | Name Import // 一个“命名”的导出 export const name value import { name } from ...❌ 错误示例&#xff1a; export…