[pkg] encoding/json
此篇為各筆記之整理,非原創內容,資料來源可見下方連結與文後參考資料:
TL;DR
json.Unmarshal
把 json 字串轉成 structjson.Marshal
把 struct 轉成 json 字串
將 struct 轉成 JSON
定義可轉換成 JSON 的 struct
透過 struct field's tag 可以將 struct 轉換成特定的格式:
// struct fields tag: `json:"<field>,<options>"`
type Book struct {
BookID uint `json:"-"` // 轉換時總是忽略掉此欄位
Title string `json:"title"` // 轉換後 JSON 的欄位名稱是 title
Author string `json:"author"` // 轉換後 JSON 的欄位名稱是 author
Name string `json:"name,omitempty"` // 當 name 是空值時轉換後則無該欄位
Age uint `json:",omitempty"` // 當 Age 有值時,則 JSON 的欄位名稱是 "Age"(大寫開頭),否則不顯示該欄位
Price uint `json:"_,"` // 轉換後 JSON 的欄位名稱是 _
Configuration string `json:"configuration,string"`
}
-
:field tag 如果是-
則總是忽略掉該欄位,轉換後不會有該欄位- 在 options 可以有一寫特殊的選項:
omitempty
:- 只會作用在 Marshal 成 JSON 時
- 意思是:如果該 field 是 zero value,則輸出的 JSON 會沒有該屬性
string
:如果某欄位的值又是 JSON 的話,可以在 options 中使用string
omitempty
omitempty
只作用在 Marshal 成 JSON 時,且該欄位的值要是「zero value」才會被 omit。
使用 Marshal 方法
- 把 struct 放入
json.Marshal(struct)
的方法中,會回傳 byte slice - 透過
string(byteSlice)
把 byte slice 轉成 string 即可得到 JSON - 在將 struct 轉換成 JSON 時會根據不同的型別轉換出不同的內容,多數的轉換都相當直覺能夠直接對應(例如 int 變成 number),比較特別的是
[]byte
會轉換成 base64-encoded 的字串nil
會轉換 成null
注意
需要留意,使用 json.Marshal()
時,只有 struct 中 public 的欄位(大寫開頭)會被轉換。
type Book struct {
BookID uint `json:"-"`
Title string `json:"title"`
Author string `json:"author"`
Name string `json:"Name,omitempty"`
Age uint `json:",omitempty"`
Price uint `json:"_,"`
}
func main() {
book := Book{BookID: 2, Title: "Learning Go", Author: "Gopher", Name: "", Age: 0, Price: 31900}
/* 將 struct 轉成 byte slice,再透過 string 變成 JSON 格 式 */
byteSlice, _ := json.MarshalIndent(book, "", " ")
fmt.Println(string(byteSlice))
//{
// "title": "Learning Go",
// "author": "Gopher",
// "_": 31900
//}
}
Nested Object
// Book struct 裡包含 Author struct
type Book struct {
Title string `json:"title"`
Author Author `json:"author"`
}
type Author struct {
Sales int `json:"book_sales"`
Age int `json:"age"`
Developer bool `json:"is_developer"`
}
func main() {
author := Author{
Sales: 3,
Age: 25,
Developer: true,
}
book := Book{Title: "Learning Go", Author: author}
/* 將 struct 轉成 byte slice,再透過 string 變成 JSON 格式 */
byteSlice, _ := json.MarshalIndent(book, "", " ")
fmt.Println(string(byteSlice))
// {
// "title": "Learning Go",
// "author": {
// "book_sales": 3,
// "age": 25,
// "is_developer": true
// }
// }
}
將 JSON 轉成 struct:結構化資料
- 定義 JSON 檔案轉換後的 struct
- 將 JSON 轉成 byte slice
- 透過
json.Unmarshal(byte_slice, &struct)
將 byte slice 轉成 struct- 如果該欄位在 JSON 中不存在,或者該欄位的值是 null,則都會用 zero value 來填補
⚠️ 如果要接收來自 JavaScript 時間格式,建議傳送 ISO 8601 的格式(而非時間戳記)會比較簡單,也就是
new Date().toISOString()
,如果傳送的是 timestamp 可能會需要另外處理。
type SensorReading struct {
Name string `json:"name"`
Capacity int `json:"capacity"`
Time time.Time `json:"time"`
}
func main() {
jsonString := `{"name": "battery sensor", "capacity": 40, "time": "2019-01-21T19:07:28Z"}`
reading := SensorReading{}
/**
* 將 JSON 轉成 struct 需要先把 string 轉成 byte slice,
* 然後再透過 Unmarshal 把空的 Struct 帶入
**/
err := json.Unmarshal([]byte(jsonString), &reading)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%+v\n", reading)
// {Name:battery sensor Capacity:40 Time:2019-01-21 19:07:28 +0000 UTC}
}
將 JSON 轉成 map:非結構化資料(unstructured data)
有些時候並沒有辦法事先知道 JSON 資料的格式會長什麼樣子,這時候可以使用 map[string]interface{}
這種寫法,如此將可以把 JSON 轉成 map:
type SensorReading struct {
Name string `json:"name"`
Capacity int `json:"capacity"`
Time string `json:"time"`
}
func main() {
jsonString := `{"name": "battery sensor", "capacity": 40, "time": "2019-01-21T19:07:28Z"}`
reading := make(map[string]interface{})
/* 將 JSON 轉成 struct 需要先把 string 轉成 byte slice,然後再透過 Unmarshal 把空的 Struct 帶入 */
err := json.Unmarshal([]byte(jsonString), &reading)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%+v\n", reading)
// map[capacity:40 name:battery sensor time:2019-01-21T19:07:28Z]
}