首頁 > 軟體

自定義Go Json的序列化方法譯文

2022-06-17 18:03:24

編譯自 Custom JSON Marshalling in Go

前言

我們知道,通過tag,可以有條件地實現客製化Go JSON序列化的方式,比如json:",omitempty", 當欄位的值為空的時候,我們可以在序列化後的資料中不包含這個值,而json:"-"可以直接不被JSON序列化,如果想被序列化key-,可以設定tag為json:"-,",加個逗號。

如果你為型別實現了MarshalJSON() ([]byte, error)和UnmarshalJSON(b []byte) error方法,那麼這個型別在序列化反序列化時將採用你客製化的方法。

這些都是我們常用的設定技巧。

如果臨時想為一個struct增加一個欄位的話,可以採用本譯文的技巧,臨時建立一個型別,通過嵌入原型別的方式來實現。他和JSON and struct composition in Go一文中介紹的技巧還不一樣(譯文和jsoniter-go擴充套件可以閱讀陶文的Golang 中使用 JSON 的一些小技巧)。JSON and struct composition in Go一文中是通過嵌入的方式建立一個新的型別,你序列化和反序列化的時候需要使用這個新型別,而本譯文中的方法是無痛改變原型別的MarshalJSON方式,採用Alias方式避免遞迴解析,確實是一種非常巧妙的方法。

以下是譯文

Go的 encoding/json序列化strcut到JSON資料:

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()},
	)
}

序列化的結果

{"id":1,"name":"Ken","lastSeen":"2009-11-10T23:00:00Z"}

但是如果我們想改變一個欄位的顯示結果我們要怎麼做呢?例如,我們想把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(),
	})
}

這樣做當然沒有問題,但是如果有很多欄位的話就會很麻煩,如果我們能把原始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方法,這會導致這個方法進入無限迴圈中,最後堆疊溢位。

解決辦法就是為原始型別起一個別名,別名會有原始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),
	})
}

同樣的技術也可以應用於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的序列化方法譯文的詳細內容,更多關於Go Json序列化自定義的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com