自定義Go?Json的序列化方法譯文
編譯自 Custom JSON Marshalling in Go。
前言
我們知道,通過tag,可以有條件地實(shí)現(xiàn)定制Go JSON序列化的方式,比如json:",omitempty", 當(dāng)字段的值為空的時(shí)候,我們可以在序列化后的數(shù)據(jù)中不包含這個(gè)值,而json:"-"可以直接不被JSON序列化,如果想被序列化key-,可以設(shè)置tag為json:"-,",加個(gè)逗號(hào)。
如果你為類型實(shí)現(xiàn)了MarshalJSON() ([]byte, error)和UnmarshalJSON(b []byte) error方法,那么這個(gè)類型在序列化反序列化時(shí)將采用你定制的方法。
這些都是我們常用的設(shè)置技巧。
如果臨時(shí)想為一個(gè)struct增加一個(gè)字段的話,可以采用本譯文的技巧,臨時(shí)創(chuàng)建一個(gè)類型,通過嵌入原類型的方式來實(shí)現(xiàn)。他和JSON and struct composition in Go一文中介紹的技巧還不一樣(譯文和jsoniter-go擴(kuò)展可以閱讀陶文的Golang 中使用 JSON 的一些小技巧)。JSON and struct composition in Go一文中是通過嵌入的方式創(chuàng)建一個(gè)新的類型,你序列化和反序列化的時(shí)候需要使用這個(gè)新類型,而本譯文中的方法是無痛改變?cè)愋偷腗arshalJSON方式,采用Alias方式避免遞歸解析,確實(shí)是一種非常巧妙的方法。
以下是譯文
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"}
但是如果我們想改變一個(gè)字段的顯示結(jié)果我們要怎么做呢?例如,我們想把LastSeen顯示為unix時(shí)間戳。
最簡(jiǎn)單的方式是引入另外一個(gè)輔助struct,在MarshalJSON中使用它進(jìn)行正確的格式化:
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)然沒有問題,但是如果有很多字段的話就會(huì)很麻煩,如果我們能把原始struct嵌入到新的struct中,并讓它繼承所有不需要改變的字段就太好了:
func (u *MyUser) MarshalJSON() ([]byte, error) { return json.Marshal(&struct { LastSeen int64 `json:"lastSeen"` *MyUser }{ LastSeen: u.LastSeen.Unix(), MyUser: u, }) }
但是等等,問題是這個(gè)輔助struct也會(huì)繼承原始struct的MarshalJSON方法,這會(huì)導(dǎo)致這個(gè)方法進(jìn)入無限循環(huán)中,最后堆棧溢出。
解決辦法就是為原始類型起一個(gè)別名,別名會(huì)有原始struct所有的字段,但是不會(huì)繼承它的方法:
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的序列化方法譯文的詳細(xì)內(nèi)容,更多關(guān)于Go Json序列化自定義的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一文帶你輕松學(xué)會(huì)Go語(yǔ)言動(dòng)態(tài)調(diào)用函數(shù)
這篇文章主要是帶大家學(xué)習(xí)一下Go語(yǔ)言是如何動(dòng)態(tài)調(diào)用函數(shù)的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的可以參考下2022-11-11GoFrame框架garray對(duì)比PHP的array優(yōu)勢(shì)
這篇文章主要為大家介紹了GoFrame框架garray對(duì)比PHP的array優(yōu)勢(shì)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步
這篇文章主要為大家詳細(xì)介紹了如何利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以參考一下2023-05-05go單體日志采集zincsearch方案實(shí)現(xiàn)
這篇文章主要為大家介紹了go單體日志采集zincsearch方案實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07