JavaScript 物件表示法(JSON)是一種用於傳送和接收結構化資訊的標準協定。在類似的協定中,JSON 並不是唯一的一個標準協定。 XML、ASN.1 和 Google 的 Protocol Buffers 都是類似的協定,並且有各自的特色,但是由於簡潔性、可讀性和流行程度等原因,JSON 是應用最廣泛的一個。
Go語言對於這些標準格式的編碼和解碼都有良好的支援,由標準庫中的 encoding/json、encoding/xml、encoding/asn1 等包提供支援,並且這類包都有著相似的 API 介面。
基本的 JSON 型別有數位(十進位制或科學記數法)、布林值(true 或 false)、字串,其中字串是以雙引號包含的 Unicode 字元序列,支援和Go語言類似的反斜槓跳脫特性,不過 JSON 使用的是 Uhhhh 跳脫數位來表示一個 UTF-16 編碼,而不是Go語言的 rune 型別。
手機擁有螢幕、電池、指紋識別等資訊,將這些資訊填充為 JSON 格式的資料。如果需要選擇性地分離 JSON 中的資料則較為麻煩。Go語言中的匿名結構體可以方便地完成這個操作。
首先給出完整的程式碼,然後再講解每個部分。
package main
import (
"encoding/json"
"fmt"
)
// 定義手機螢幕
type Screen struct {
Size float32 // 螢幕尺寸
ResX, ResY int // 螢幕水平和垂直解析度
}
// 定義電池
type Battery struct {
Capacity int // 容量
}
// 生成json資料
func genJsonData() []byte {
// 完整資料結構
raw := &struct {
Screen
Battery
HasTouchID bool // 序列化時新增的欄位:是否有指紋識別
}{
// 螢幕引數
Screen: Screen{
Size: 5.5,
ResX: 1920,
ResY: 1080,
},
// 電池引數
Battery: Battery{
2910,
},
// 是否有指紋識別
HasTouchID: true,
}
// 將資料序列化為json
jsonData, _ := json.Marshal(raw)
return jsonData
}
func main() {
// 生成一段json資料
jsonData := genJsonData()
fmt.Println(string(jsonData))
// 只需要螢幕和指紋識別資訊的結構和範例
screenAndTouch := struct {
Screen
HasTouchID bool
}{}
// 反序列化到screenAndTouch
json.Unmarshal(jsonData, &screenAndTouch)
// 輸出screenAndTouch的詳細結構
fmt.Printf("%+vn", screenAndTouch)
// 只需要電池和指紋識別資訊的結構和範例
batteryAndTouch := struct {
Battery
HasTouchID bool
}{}
// 反序列化到batteryAndTouch
json.Unmarshal(jsonData, &batteryAndTouch)
// 輸出screenAndTouch的詳細結構
fmt.Printf("%+vn", batteryAndTouch)
}
定義資料結構
首先,定義手機的各種資料結構體,如螢幕和電池,參考如下程式碼:
// 定義手機螢幕
type Screen struct {
Size float32 // 螢幕尺寸
ResX, ResY int // 螢幕水平和垂直解析度
}
// 定義電池
type Battery struct {
Capacity int // 容量
}
上面程式碼定義了螢幕結構體和電池結構體,它們分別描述螢幕和電池的各種細節引數。
準備 JSON 資料
準備手機資料結構,填充資料,將資料序列化為 JSON 格式的位元組陣列,程式碼如下:
// 生成JSON資料
func genJsonData() []byte {
// 完整資料結構
raw := &struct {
Screen
Battery
HasTouchID bool // 序列化時新增的欄位:是否有指紋識別
}{
// 螢幕引數
Screen: Screen{
Size: 5.5,
ResX: 1920,
ResY: 1080,
},
// 電池引數
Battery: Battery{
2910,
},
// 是否有指紋識別
HasTouchID: true,
}
// 將資料序列化為JSON
jsonData, _ := json.Marshal(raw)
return jsonData
}
程式碼說明如下:
-
第 4 行定義了一個匿名結構體。這個結構體內嵌了 Screen 和 Battery 結構體,同時臨時加入了 HasTouchID 欄位。
-
第 10 行,為剛宣告的匿名結構體填充螢幕資料。
-
第 17 行,填充電池資料。
-
第 22 行,填充指紋識別欄位。
-
第 26 行,使用 json.Marshal 進行 JSON 序列化,將 raw 變數序列化為 []byte 格式的 JSON 資料。
分離JSON資料
呼叫 genJsonData 獲得 JSON 資料,將需要的欄位填充到匿名結構體範例中,通過 json.Unmarshal 反序列化 JSON 資料達成分離 JSON 資料效果。程式碼如下:
func main() {
// 生成一段JSON資料
jsonData := genJsonData()
fmt.Println(string(jsonData))
// 只需要螢幕和指紋識別資訊的結構和範例
screenAndTouch := struct {
Screen
HasTouchID bool
}{}
// 反序列化到screenAndTouch中
json.Unmarshal(jsonData, &screenAndTouch)
// 輸出screenAndTouch的詳細結構
fmt.Printf("%+vn", screenAndTouch)
// 只需要電池和指紋識別資訊的結構和範例
batteryAndTouch := struct {
Battery
HasTouchID bool
}{}
// 反序列化到batteryAndTouch
json.Unmarshal(jsonData, &batteryAndTouch)
// 輸出screenAndTouch的詳細結構
fmt.Printf("%+vn", batteryAndTouch)
}
程式碼說明如下:
-
第 4 行,呼叫 genJsonData() 函數,獲得 []byte 型別的 JSON 資料。
-
第 6 行,將 jsonData 的 []byte 型別的 JSON 資料轉換為字串格式並列印輸出。
-
第 9 行,構造匿名結構體,填充 Screen 結構和 HasTouchID 欄位,第 12 行中的 {} 表示將結構體範例化。
-
第 15 行,呼叫 json.Unmarshal,輸入完整的 JSON 資料(jsonData),將資料按第 9 行定義的結構體格式序列化到 screenAndTouch 中。
-
第 18 行,列印輸出 screenAndTouch 中的詳細資料資訊。
-
第 21 行,構造匿名結構體,填充 Battery 結構和 HasTouchID 欄位。
-
第 27 行,呼叫 json.Unmarshal,輸入完整的 JSON 資料(jsonData),將資料按第 21 行定義的結構體格式序列化到 batteryAndTouch 中。
-
第 30 行,列印輸出 batteryAndTouch 的詳細資料資訊。