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.pswp.cn/diannao/13068.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/13068.shtml
英文地址,請注明出處:http://en.pswp.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…