自定義Go?Json的序列化方法譯文
編譯自 Custom JSON Marshalling in Go。
前言
我們知道,通過tag,可以有條件地實現(xiàn)定制Go JSON序列化的方式,比如json:",omitempty", 當(dāng)字段的值為空的時候,我們可以在序列化后的數(shù)據(jù)中不包含這個值,而json:"-"可以直接不被JSON序列化,如果想被序列化key-,可以設(shè)置tag為json:"-,",加個逗號。
如果你為類型實現(xiàn)了MarshalJSON() ([]byte, error)和UnmarshalJSON(b []byte) error方法,那么這個類型在序列化反序列化時將采用你定制的方法。
這些都是我們常用的設(shè)置技巧。
如果臨時想為一個struct增加一個字段的話,可以采用本譯文的技巧,臨時創(chuàng)建一個類型,通過嵌入原類型的方式來實現(xiàn)。他和JSON and struct composition in Go一文中介紹的技巧還不一樣(譯文和jsoniter-go擴展可以閱讀陶文的Golang 中使用 JSON 的一些小技巧)。JSON and struct composition in Go一文中是通過嵌入的方式創(chuàng)建一個新的類型,你序列化和反序列化的時候需要使用這個新類型,而本譯文中的方法是無痛改變原類型的MarshalJSON方式,采用Alias方式避免遞歸解析,確實是一種非常巧妙的方法。
以下是譯文
Go的 encoding/json序列化strcut到JSON數(shù)據(jù):
package main
import (
"encoding/json"
"os"
"time"
)
type MyUser struct {
ID int64 `json:"id"`
Name string `json:"name"`
LastSeen time.Time `json:"lastSeen"`
}
func main() {
_ = json.NewEncoder(os.Stdout).Encode(
&MyUser{1, "Ken", time.Now()},
)
}序列化的結(jié)果
{"id":1,"name":"Ken","lastSeen":"2009-11-10T23:00:00Z"}
但是如果我們想改變一個字段的顯示結(jié)果我們要怎么做呢?例如,我們想把LastSeen顯示為unix時間戳。
最簡單的方式是引入另外一個輔助struct,在MarshalJSON中使用它進行正確的格式化:
func (u *MyUser) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int64 `json:"id"`
Name string `json:"name"`
LastSeen int64 `json:"lastSeen"`
}{
ID: u.ID,
Name: u.Name,
LastSeen: u.LastSeen.Unix(),
})
}這樣做當(dāng)然沒有問題,但是如果有很多字段的話就會很麻煩,如果我們能把原始struct嵌入到新的struct中,并讓它繼承所有不需要改變的字段就太好了:
func (u *MyUser) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
LastSeen int64 `json:"lastSeen"`
*MyUser
}{
LastSeen: u.LastSeen.Unix(),
MyUser: u,
})
}但是等等,問題是這個輔助struct也會繼承原始struct的MarshalJSON方法,這會導(dǎo)致這個方法進入無限循環(huán)中,最后堆棧溢出。
解決辦法就是為原始類型起一個別名,別名會有原始struct所有的字段,但是不會繼承它的方法:
func (u *MyUser) MarshalJSON() ([]byte, error) {
type Alias MyUser
return json.Marshal(&struct {
LastSeen int64 `json:"lastSeen"`
*Alias
}{
LastSeen: u.LastSeen.Unix(),
Alias: (*Alias)(u),
})
}同樣的技術(shù)也可以應(yīng)用于UnmarshalJSON方法:
func (u *MyUser) UnmarshalJSON(data []byte) error {
type Alias MyUser
aux := &struct {
LastSeen int64 `json:"lastSeen"`
*Alias
}{
Alias: (*Alias)(u),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
u.LastSeen = time.Unix(aux.LastSeen, 0)
return nil
}以上就是自定義Go Json的序列化方法譯文的詳細內(nèi)容,更多關(guān)于Go Json序列化自定義的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
idea搭建go環(huán)境實現(xiàn)go語言開發(fā)
這篇文章主要給大家介紹了關(guān)于idea搭建go環(huán)境實現(xiàn)go語言開發(fā)的相關(guān)資料,文中通過圖文介紹以及代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用go具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01
Go實現(xiàn)map并發(fā)安全的3種方式總結(jié)
Go的原生map不是并發(fā)安全的,在多協(xié)程讀寫同一個map的時候,安全性無法得到保障,這篇文章主要給大家總結(jié)介紹了關(guān)于Go實現(xiàn)map并發(fā)安全的3種方式,需要的朋友可以參考下2023-10-10
Go語言中使用flag包對命令行進行參數(shù)解析的方法
這篇文章主要介紹了Go語言中使用flag包對命令行進行參數(shù)解析的方法,文中舉了一個實現(xiàn)flag.Value接口來自定義flag的例子,需要的朋友可以參考下2016-04-04
基于go interface{}==nil 的幾種坑及原理分析
這篇文章主要介紹了基于go interface{}==nil 的幾種坑及原理分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
Golang中fsnotify包監(jiān)聽文件變化的原理詳解
Golang提供了一個強大的fsnotify包,它能夠幫助我們輕松實現(xiàn)文件系統(tǒng)的監(jiān)控,本文將深入探討fsnotify包的原理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12

