golang MarshalJson的實(shí)現(xiàn)
在 Go 語言中,MarshalJSON 是一個(gè)接口方法,允許自定義類型在進(jìn)行 JSON 編碼時(shí)提供自定義的序列化邏輯。通過實(shí)現(xiàn) MarshalJSON 方法,你可以控制結(jié)構(gòu)體或其他類型在轉(zhuǎn)換為 JSON 時(shí)的表現(xiàn)。
基本用法
當(dāng)你想要自定義某個(gè)類型的 JSON 表現(xiàn)時(shí),可以實(shí)現(xiàn) json.Marshaler 接口,該接口只包含一個(gè)方法 MarshalJSON。實(shí)現(xiàn)該方法后,使用 json.Marshal 函數(shù)時(shí)會(huì)自動(dòng)調(diào)用你定義的 MarshalJSON 方法。
示例
以下是一個(gè)示例,展示如何自定義結(jié)構(gòu)體的 JSON 序列化:
package main
import (
"encoding/json"
"fmt"
)
// 定義一個(gè)結(jié)構(gòu)體
type User struct {
Name string
Age int
Email string
}
// 為 User 實(shí)現(xiàn) MarshalJSON 方法
func (u User) MarshalJSON() ([]byte, error) {
// 自定義 JSON 輸出格式
return json.Marshal(struct {
FullName string `json:"name"`
Age int `json:"age"`
Email string `json:"email_address"`
}{
FullName: u.Name,
Age: u.Age,
Email: u.Email,
})
}
func main() {
user := User{Name: "Alice", Age: 30, Email: "alice@example.com"}
// Marshal 用戶對(duì)象為 JSON
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("Error marshaling to JSON:", err)
return
}
fmt.Println(string(jsonData)) // 輸出: {"name":"Alice","age":30,"email_address":"alice@example.com"}
}
解釋
- 定義結(jié)構(gòu)體:我們定義了一個(gè)
User結(jié)構(gòu)體,包含Name、Age和Email字段。 - 實(shí)現(xiàn)
MarshalJSON方法:我們?yōu)?nbsp;User結(jié)構(gòu)體實(shí)現(xiàn)了MarshalJSON方法。在這個(gè)方法中,我們自定義了 JSON 輸出格式。 - 自定義輸出:在
MarshalJSON方法中,我們使用匿名結(jié)構(gòu)體來定義最終的 JSON 格式。 - 使用
json.Marshal:在main函數(shù)中,我們創(chuàng)建了一個(gè)User實(shí)例,并使用json.Marshal將其轉(zhuǎn)換為 JSON 字符串。
注意事項(xiàng)
- 錯(cuò)誤處理:
MarshalJSON方法應(yīng)返回error,以便在序列化過程中可以處理潛在的錯(cuò)誤。 - 遞歸調(diào)用:在
MarshalJSON方法中,如果調(diào)用json.Marshal,需要確保所處理的結(jié)構(gòu)體不會(huì)遞歸調(diào)用自身的MarshalJSON方法。
Marshal函數(shù)將會(huì)遞歸遍歷整個(gè)對(duì)象,依次按成員類型對(duì)這個(gè)對(duì)象進(jìn)行編碼。
類型轉(zhuǎn)換規(guī)則如下:
- bool類型:轉(zhuǎn)換為JSON的Boolean
- 整數(shù)、浮點(diǎn)數(shù)等數(shù)值類型: 轉(zhuǎn)換為JSON的Number
- string類型: 轉(zhuǎn)換為JSON的字符串(帶""引號(hào))
- struct類型:轉(zhuǎn)換為JSON的Object,再根據(jù)各個(gè)成員的類型遞歸打包
- 數(shù)組或切片類型: 轉(zhuǎn)換為JSON的Array
- []byte類型: 會(huì)先進(jìn)行base64編碼然后轉(zhuǎn)換為JSON字符串
- map類型:轉(zhuǎn)換為JSON的Object,key必須是string
- interface{}類型: 按照內(nèi)部的實(shí)際類型進(jìn)行轉(zhuǎn)換
- nil類型: 轉(zhuǎn)為JSON的null
- channel,func等類型: 會(huì)返回UnsupportedTypeError
從golang到j(luò)son:
| golang | json |
|---|---|
| bool | Boolean |
| int、float等數(shù)字 | Number |
| string | String |
| []byte(base64編碼) | String |
| struct | Object,再遞歸打包 |
| array/slice | Array |
| map | Object |
| interface{} | 按實(shí)際類型轉(zhuǎn)換 |
| nil | null |
| channel,func | UnsupportedTypeError |
從json到golang:
| json | golang |
|---|---|
| Boolean | bool |
| Number | float64 |
| String | string |
| Array | []interface{} |
| Object | map[string]interface{} |
| null | nil |
避坑
json.marshal使用不當(dāng),會(huì)存在base64編碼問題問題出現(xiàn)在:[]byte 在json.marshal時(shí)會(huì)進(jìn)行base64 encoding處理
解決辦法:使用json.RawMessagejson.RawMessage其實(shí)就是[]byte類型的重定義??梢赃M(jìn)行強(qiáng)制類型轉(zhuǎn)換。
現(xiàn)在有這么一種場(chǎng)景,結(jié)構(gòu)體中的其中一個(gè)字段的格式是未知的:
type Command struct {
ID int
Cmd string
Args *json.RawMessage
}
使用json.RawMessage的話,Args字段在Unmarshal時(shí)不會(huì)被解析,直接將字節(jié)數(shù)據(jù)賦值給Args。我們可以能先解包第一層的JSON數(shù)據(jù),然后根據(jù)Cmd的值,再確定Args的具體類型進(jìn)行第二次Unmarshal。
注意:一定要使用指針類型
*json.RawMessage,否則在Args會(huì)被認(rèn)為是[]byte類型,在打包時(shí)會(huì)被打包成base64編碼的字符串。
使用interface{}, interface{}類型在Unmarshal時(shí),會(huì)自動(dòng)將JSON轉(zhuǎn)換為對(duì)應(yīng)的數(shù)據(jù)類型:
JSON的boolean: 轉(zhuǎn)換為bool
JSON的數(shù)值: 轉(zhuǎn)換為float64
JSON的字符串: 轉(zhuǎn)換為string
JSON的Array: 轉(zhuǎn)換為[]interface{}
JSON的Object: 轉(zhuǎn)換為map[string]interface{}
JSON的null: 轉(zhuǎn)換為nil
需要注意的有兩個(gè):
- 一是所有的JSON數(shù)值自動(dòng)轉(zhuǎn)換為float64類型,使用時(shí)需要再手動(dòng)轉(zhuǎn)換為需要的int,int64等類型。
- 二是JSON的object自動(dòng)轉(zhuǎn)換為
map[string]interface{}類型,訪問時(shí)直接用JSON Object的字段名作為key進(jìn)行訪問。在不知道JSON數(shù)據(jù)的格式時(shí),可以使用interface{}。
自定義類型:如果希望自己定義對(duì)象的打包解包方式,可以實(shí)現(xiàn)以下的接口:
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
實(shí)現(xiàn)該接口的對(duì)象需要將自己的數(shù)據(jù)打包和解包。如果實(shí)現(xiàn)了該接口,json在打包解包時(shí)則會(huì)調(diào)用自定義的方法,不再對(duì)該對(duì)象進(jìn)行其他處理。
總結(jié)
通過實(shí)現(xiàn) MarshalJSON 方法,可以為 Go 的自定義類型提供靈活的 JSON 序列化控制。這使得在與 JSON 數(shù)據(jù)交互時(shí),可以更好地控制數(shù)據(jù)的結(jié)構(gòu)和格式。
到此這篇關(guān)于golang MarshalJson的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang MarshalJson內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Go語言JSON編解碼神器之marshal的運(yùn)用
- 淺談golang的json.Unmarshal的坑
- Golang?中的json.Marshal問題總結(jié)(推薦)
- Go?json自定義Unmarshal避免判斷nil示例詳解
- Go語言利用Unmarshal解析json字符串的實(shí)現(xiàn)
- Go處理json數(shù)據(jù)方法詳解(Marshal,UnMarshal)
- Golang語言JSON解碼函數(shù)Unmarshal的使用
- Go 使用Unmarshal將json賦給struct出錯(cuò)的原因及解決
- Go 語言json.Unmarshal 遇到的小問題(推薦)
相關(guān)文章
Go的gin參數(shù)校驗(yàn)中的validator庫(kù)詳解
這篇文章主要介紹了Go的gin參數(shù)校驗(yàn)之validator庫(kù),使用 validator 以后,只需要在定義結(jié)構(gòu)體時(shí)使用 binding 或 validate tag標(biāo)識(shí)相關(guān)校驗(yàn)規(guī)則,就可以進(jìn)行參數(shù)校驗(yàn)了,而不用自己?jiǎn)为?dú)去寫常見的校驗(yàn)規(guī)則,需要的朋友可以參考下2023-08-08
Go?tablewriter庫(kù)提升命令行輸出專業(yè)度實(shí)例詳解
命令行工具大家都用過,如果是運(yùn)維人員可能會(huì)編寫命令行工具來完成各種任務(wù),命令行輸出的美觀和易讀性往往容易被忽視,很爛的輸出會(huì)讓人感覺不專業(yè),本文將介紹Go語言中牛逼的實(shí)戰(zhàn)工具tablewriter庫(kù),使你在命令行輸出中展現(xiàn)出專業(yè)的一面2023-11-11
golang gopm get -g -v 無法獲取第三方庫(kù)的解決方案
這篇文章主要介紹了golang gopm get -g -v 無法獲取第三方庫(kù)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-05-05
輕松入門:使用Golang開發(fā)跨平臺(tái)GUI應(yīng)用
Golang是一種強(qiáng)大的編程語言,它的并發(fā)性和高性能使其成為開發(fā)GUI桌面應(yīng)用的理想選擇,Golang提供了豐富的標(biāo)準(zhǔn)庫(kù)和第三方庫(kù),可以輕松地創(chuàng)建跨平臺(tái)的GUI應(yīng)用程序,通過使用Golang的GUI庫(kù),開發(fā)人員可以快速構(gòu)建具有豐富用戶界面和交互功能的應(yīng)用程序,需要的朋友可以參考下2023-10-10
golang簡(jiǎn)單獲取上傳文件大小的實(shí)現(xiàn)代碼
這篇文章主要介紹了golang簡(jiǎn)單獲取上傳文件大小的方法,涉及Go語言文件傳輸及文件屬性操作的相關(guān)技巧,需要的朋友可以參考下2016-07-07
使用golang引入外部包的三種方式:go get, go module, ve
這篇文章主要介紹了使用golang引入外部包的三種方式:go get, go module, vendor目錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01

