<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
有如下一個例子:
package main import ( "encoding/json" "fmt" "time" ) type RecordBrief struct { time.Time ID int } func main() { r := RecordBrief{ Time: time.Now(), ID: 6, } m, _ := json.MarshalIndent(r, "", "t") fmt.Println(string(m)) }
你期望的結果是像:
{
"Time": "2022-06-25T10:49:39.597537249+08:00",
"ID": 6
}
還是:
{
"ID": 6
}
或者是別的?
其實如果你認為的答案不是:
"2022-06-25T10:52:23.590933959+08:00"
也沒能想明白原因,可以繼續往下看看。
誠然,我們在學習json的序列化和反序列化的時候,目的就是把一個Golang struct值序列化為對應的json string罷了。可能我們還知道一些Marshal的規則,比如struct的欄位需要定義為可匯出的,比如還可通過定義對應的json tag來修改struct field對應的json欄位名稱等。
但是對於json.Marshal
函數的細節可能大家不會去太在意。本次提出的問題中,我們不難注意到其中的time.Time是一個匿名(Anonymous)欄位,而這個就是答案的由來。我們先看看json.Marshal
的註釋檔案中的一個解釋:
// ... // Marshal traverses the value v recursively. // If an encountered value implements the Marshaler interface // and is not a nil pointer, Marshal calls its MarshalJSON method // to produce JSON. If no MarshalJSON method is present but the // value implements encoding.TextMarshaler instead, Marshal calls // its MarshalText method and encodes the result as a JSON string. // ... func Marshal(v interface{}) ([]byte, error) { ... }
Marshal
函數遞迴地遍歷傳入的序列化物件v
(及其成員)。當面對一個實現了json.Marshaler
介面的物件(不能是一個空指標)時,Marshal
函數就會呼叫該物件的MarshalJSON
方法來生成JSON內容。如果沒有實現json.Marshaler
,而是實現了encoding.TextMarshaler
介面,那麼就會呼叫它的MarshalText
方法,然後把該方法返回的結果轉編為一個JSON字串。
然後我們再看看time.Time
:
type Time struct { ... } // MarshalJSON implements the json.Marshaler interface. // The time is a quoted string in RFC 3339 format, with sub-second precision added if present. func (t Time) MarshalJSON() ([]byte, error) { if y := t.Year(); y < 0 || y >= 10000 { // RFC 3339 is clear that years are 4 digits exactly. // See golang.org/issue/4556#c15 for more discussion. return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]") } b := make([]byte, 0, len(RFC3339Nano)+2) b = append(b, '"') b = t.AppendFormat(b, RFC3339Nano) b = append(b, '"') return b, nil }
所以time.Time
是實現了json.Marshaler
介面的。然後觀察到它的實現是把時間按照RFC3339Nano
格式字串值返回為json序列化結果,這和我們實際上執行程式看到的結果是一致的。
那麼再看看我們的type定義:
type RecordBrief struct { time.Time ID int }
為什麼ID
欄位不見了?正是因為匿名欄位的原因,Golang中的這種用法有點類似於繼承,所以RecordBrief
型別也自動具有了time.Time
的所有方法,當然也包括了MarshalJSON
,從而也就實現了json.Marshaler
介面。如此一來,當一個RecordBrief
被Marshal的時候,它的序列化結果就被time.Time
的序列化結果給覆蓋了。
如果你和我一樣,沒能一下知道原因,那多半是對一些常見的知識瞭解的深度和廣度不夠。我之前確實不知道time.Time
居然也實現了json.Marshaler
介面,也不清楚json.Marshal
到底在做什麼,所以不知道答案也就理所當然了,後來經過閱讀檔案註釋,才終於對該問題有了一些認知(後續應該總結一篇json.Marshal
的原始碼解析)。
至此,如果我們想要這種樣子的結果:
{
"Time": "2022-06-25T10:49:39.597537249+08:00",
"ID": 6
}
最簡單的方式是修改struct,將time.Time
作為一個非匿名的匯出欄位:
type RecordBrief struct { Time time.Time ID int }
另一種方法是給我們的RecordBrief
實現json.Marshaler
介面:
type RecordBrief struct { time.Time ID int } func (r RecordBrief) MarshalJSON() ([]byte, error) { //非常簡單的一種方式就是建立中間型別 t := struct { Time time.Time ID int }{ r.Time, r.ID, } return json.Marshal(t) }
到此這篇關於Golang 中的json.Marshal問題總結的文章就介紹到這了,更多相關Golang json.Marshal內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45