WOMEN_WHO_GO_SEATTLE.png
大家好,我叫謝偉,是一名程序員。
近期我會持續更新內置庫的學習筆記,主要參考的是文檔 godoc 和 內置庫的源碼
在日常開發過程中,使用最頻繁的當然是內置庫,無數的開源項目,無不是在內置庫的基礎之上進行衍生、開發,所以其實是有很大的必要進行梳理學習。
本節的主題:內置庫 json
大綱:
- 自己總結的使用方法
- 官方支持的API
- 學到了什麼
自己總結的用法
既然是 json 操作,那麼核心應該是包括兩個方面:
- 序列化:go 數據類型轉換爲 json
- 反序列化:json 轉換爲 go 數據類型
對應的方法:
- func Marshal(v interface{}) ([]byte, error)
- func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
- func Unmarshal(data []byte, v interface{}) error
具體如何使用呢?
布爾類型
func boolToJson(ok bool) []byte { jsonResult, _ := json.Marshal(ok) return jsonResult } func jsonToBool(value []byte) bool { var goResult bool json.Unmarshal(value, &goResult) return goResult } func main(){ fmt.Println(string(boolToJson(1 == 1))) fmt.Println(jsonToBool([]byte(`true`))) } >> true true
數值型
func intToJson(value int) []byte { jsonInt, _ := json.Marshal(value) return jsonInt } func main(){ fmt.Println(string(intToJson(12))) } >> 12
結構體
結構體 轉換爲 json
type Info struct { Name string `json:"name,omitempty"` Age int `json:"age,string"` City string `json:"city_shanghai"` Company string `json:"-"` } func (i Info) MarshalOp() []byte { jsonResult, _ := json.Marshal(i) return jsonResult } func main(){ var info Info info = Info{ Name: "XieWei", Age: 100, City: "shangHai", Company: "Only Me", } fmt.Println(string(info.MarshalOp())) var otherInfo Info otherInfo.Name = "" otherInfo.Age = 20 otherInfo.City = "BeiJing" otherInfo.Company = "Only You" fmt.Println(string(otherInfo.MarshalOp())) } >> {"name":"XieWei","age":"100","city_shanghai":"shangHai"} {"age":"20","city_shanghai":"BeiJing"}
還記得我們之間講的 反射章節 結構體的 tag 嗎?
- info 結構體的 tag
- omitempty 表示該字段爲空時,不序列化
-
-
表示忽略該字段 - json 內定義了該字段序列化時顯示的字段,比如 Name 最後序列化 爲 name;比如 City 最後序列化爲 city_shanghai
- json 內還可以轉換類型,比如 age 原本 int 類型,最後轉化爲 string 類型
json 轉換爲 結構體:
func UnMarshalExample(value []byte) (result Info) { json.Unmarshal(value, &result) return result } func main(){ fmt.Println(UnMarshalExample([]byte(`{"name":"xieWei", "age": "20", "city_shanghai": "GuangDong"}`))) } >> {xieWei 20 GuangDong }
好,至此,我們常用的 json 操作就這些,主要兩個方面:Marshal 和 UnMarshal
大概講述了下 結構體的 tag 的作用:
- 比如如何定義字段名稱
- 比如如何忽略字段
- 比如如何更改類型
- 比如如何零值忽略
官方文檔
列舉幾個再常用的:
- func Valid(data []byte) bool
- type Marshaler 接口,可以自己定義序列化的返回值
- type Unmarshaler 接口,可以自己定義反序列化的返回值
Valid
判斷是否是有效的 json 格式的數據
func main(){ fmt.Println(json.Valid([]byte(`{"name":1, 2}`))) } >> false
- 表示不是標準的 json 格式的數據
Marshaler 接口,需要實現 MarshalJSON 方法
自定義序列化返回值
type Marshaler interface { MarshalJSON() ([]byte, error) }
type SelfMarshal struct { Name string Age int City string } func (self SelfMarshal) MarshalJSON() ([]byte, error) { result := fmt.Sprintf("name:--%s,age:--%d,city:--%s", self.Name, self.Age, self.City) if !json.Valid([]byte(result)) { fmt.Println("invalid") return json.Marshal(result) } return []byte(result), nil } func main(){ var self = SelfMarshal{} self.Age = 20 self.Name = "XieWei" self.City = "HangZhou" selfJsonMarshal, err := json.Marshal(self) fmt.Println(err, string(selfJsonMarshal)) } >> <nil> "name:--XieWei,age:--20,city:--HangZhou"
- 返回了自定義的序列化的格式
type jsonTime time.Time //實現它的json序列化方法 func (this jsonTime) MarshalJSON() ([]byte, error) { var stamp = fmt.Sprintf("\"%s\"", time.Time(this).Format("2006-01-02 15:04:05")) return []byte(stamp), nil } type Test struct { Date jsonTime `json:"date"` Name string `json:"name"` State bool `json:"state"` } func main(){ var t = Test{} t.Date = jsonTime(time.Now()) t.Name = "Hello World" t.State = true body, _ := json.Marshal(t) fmt.Println(string(body)) } >> {"date":"2018-11-06 22:23:19","name":"Hello World","state":true}
- 返回了自定義的序列化格式數據
總結
- 友好的 API
- 日常的序列化反序列化,內置的庫其實已經滿足要求,但是對於複雜的嵌套的數據類型,想要獲取某個字段的值則相當費勁
- 所以衍生了各種各樣的號稱高性能的 json 解析庫
各 json 解析庫性能比對 | 各 json 解析庫性能比對
收穫:
- 可以自己定義序列化、反序列化的格式
- 可以檢測 是否符合 json 類型
func (self SelfMarshal) MarshalJSON() ([]byte, error) { result := fmt.Sprintf("name:--%s,age:--%d,city:--%s", self.Name, self.Age, self.City) return []byte(result), nil }
上文代碼會報錯,爲什麼?因爲不是標準 json 格式的數據。
所以通常建議這麼做:
func (self SelfMarshal) MarshalJSON() ([]byte, error) { result := fmt.Sprintf("name:--%s,age:--%d,city:--%s", self.Name, self.Age, self.City) if !json.Valid([]byte(result)) { fmt.Println("invalid") return json.Marshal(result) } return []byte(result), nil }
即將字符串 marshal 處理。
<完>