自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

簡(jiǎn)化 Go 中對(duì) JSON 的處理

開(kāi)發(fā) 后端
在強(qiáng)類(lèi)型語(yǔ)言中,JSON 通常很難處理 —— JSON 類(lèi)型有字符串、數(shù)字、字典和數(shù)組。如果你使用的語(yǔ)言是 javascript、python、ruby 或 PHP,那么 JSON 有一個(gè)很大的好處就是在解析和編碼數(shù)據(jù)時(shí)你不需要考慮類(lèi)型。

我的第一個(gè) Go 工程需要處理一堆 JSON 測(cè)試固件并把 JSON 數(shù)據(jù)作為參數(shù)傳給我們搭建的 API 處理。另一個(gè)團(tuán)隊(duì)為了給 API 提供語(yǔ)言無(wú)關(guān)的、可預(yù)期的輸入和輸出,創(chuàng)建了這些測(cè)試固件。

在強(qiáng)類(lèi)型語(yǔ)言中,JSON 通常很難處理 —— JSON 類(lèi)型有字符串、數(shù)字、字典和數(shù)組。如果你使用的語(yǔ)言是 javascript、python、ruby 或 PHP,那么 JSON 有一個(gè)很大的好處就是在解析和編碼數(shù)據(jù)時(shí)你不需要考慮類(lèi)型。

// in PHP
$object = json_decode('{"foo":"bar"}');
// in javascript
const object = JSON.parse('{"foo":"bar"}')

在強(qiáng)類(lèi)型語(yǔ)言中,你需要自己去定義怎么處理 JSON 對(duì)象的字符串、數(shù)字、字典和數(shù)組。在 Go 語(yǔ)言中,你使用內(nèi)建的 API 時(shí)需要考慮如何更好地把一個(gè) JSON 文件轉(zhuǎn)換成 Go 的數(shù)據(jù)結(jié)構(gòu)。我不打算深入研究在 Go 中如何處理 JSON 這個(gè)復(fù)雜的話(huà)題,我只列出兩個(gè)代碼的例子來(lái)闡述下這個(gè)問(wèn)題。源碼詳情請(qǐng)見(jiàn) Go 實(shí)例教程[1]

解析/序列化為 map[string]interface

首先,來(lái)看這個(gè)程序。

package main
import (
"encoding/json"
"fmt"
)
func main() {
byt := []byte(`{
"num":6.13,
"strs":["a","b"],
"obj":{"foo":{"bar":"zip","zap":6}}
}`)
var dat map[string]interface{}
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
num := dat["num"].(float64)
fmt.Println(num)
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
fmt.Println(str1)
obj := dat["obj"].(map[string]interface{})
obj2 := obj["foo"].(map[string]interface{})
fmt.Println(obj2)
}

我們把 JSON 數(shù)據(jù)從 byt 變量反序列化(如解析、解碼等等)成名為 dat 的 map/字典對(duì)象。這些操作跟其他語(yǔ)言類(lèi)似,不同的是我們的輸入需要是字節(jié)數(shù)組(不是字符串),對(duì)于字典的每個(gè)值時(shí)需要有類(lèi)型斷言[2]才能讀取或訪問(wèn)該值。

當(dāng)我們處理一個(gè)多層嵌套的 JSON 對(duì)象時(shí),這些類(lèi)型斷言會(huì)讓處理變得非常繁瑣。

解析/序列化為 struct

第二種處理如下:

package main
import (
"encoding/json"
"fmt"
)
type ourData struct {
Num float64 `json:"num"`
Strs []string `json:"strs"`
Obj map[string]map[string]string `json:"obj"`
}
func main() {
byt := []byte(`{
"num":6.13,
"strs":["a","b"],
"obj":{"foo":{"bar":"zip","zap":6}}
}`)
res := ourData{}
json.Unmarshal(byt, &res)
fmt.Println(res.Num)
fmt.Println(res.Strs)
fmt.Println(res.Obj)
}

我們利用 Go struct 的標(biāo)簽功能把 byt 變量中的字節(jié)反序列化成一個(gè)具體的結(jié)構(gòu) ourData。

標(biāo)簽是結(jié)構(gòu)體成員定義后跟隨的字符串。我們的定義如下:

type ourData struct {
Num float64 `json:"num"`
Strs []string `json:"strs"`
Obj map[string]map[string]string `json:"obj"`
}

你可以看到 Num 成員的 JSON 標(biāo)簽 “num”、Str 成員的 JSON 標(biāo)簽 “strs”、Obj 成員的 JSON 標(biāo)簽 “obj”。這些字符串使用反引號(hào)[3]把標(biāo)簽聲明為文字串。除了反引號(hào),你也可以使用雙引號(hào),但是使用雙引號(hào)可能會(huì)需要一些額外的轉(zhuǎn)義,這樣看起來(lái)會(huì)很凌亂。

type ourData struct {
Num float64 "json:\"num\""
Strs []string "json:\"strs\""
Obj map[string]map[string]string "json:\"obj\""
}

在 struct 的定義中,標(biāo)簽不是必需的。如果你的 struct 中包含了標(biāo)簽,那么它意味著 Go 的 反射 API[4] 可以訪問(wèn)標(biāo)簽的值[5]。Go 中的包可以使用這些標(biāo)簽來(lái)進(jìn)行某些操作。

Go 的 encoding/json 包在反序列化 JSON 成員為具體的 struct 時(shí),通過(guò)這些標(biāo)簽來(lái)決定每個(gè)頂層的 JSON 成員的值。換句話(huà)說(shuō),當(dāng)你定義如下的 struct 時(shí):

type ourData struct {
Num float64 `json:"num"`
}

意味著:

  • 當(dāng)使用 json.Unmarshal 反序列化 JSON 對(duì)象為這個(gè) struct 時(shí),取它頂層的 num 成員的值并把它賦給這個(gè) struct 的 Num 成員。

這個(gè)操作可以讓你的反序列化代碼稍微簡(jiǎn)潔一點(diǎn),因?yàn)槌绦騿T不需要對(duì)每個(gè)成員取值時(shí)都顯式地調(diào)用類(lèi)型斷言。然而,這個(gè)仍不是最佳解決方案。

首先 —— 標(biāo)簽只對(duì)頂層的成員有效 —— 嵌套的 JSON 需要對(duì)應(yīng)嵌套的類(lèi)型(如 Obj map[string]map[string]string),因此繁瑣的操作仍沒(méi)有避免。

其次 —— 它假定你的 JSON 結(jié)構(gòu)不會(huì)變化。如果你運(yùn)行上面的程序,你會(huì)發(fā)現(xiàn) "zap":6 并沒(méi)有被賦值到 Obj 成員。你可以通過(guò)創(chuàng)建類(lèi)型 map[string]map[string]interface{} 來(lái)處理,但是在這里你又需要進(jìn)行類(lèi)型斷言了。

這是我第一個(gè) Go 工程遇到的情況,曾讓我苦不堪言。

幸運(yùn)的是,現(xiàn)在我們有了更有效的辦法。

SJSON 和 GJSON

Go 內(nèi)建的 JSON 處理并沒(méi)有變化,但是已經(jīng)出現(xiàn)了一些成熟的旨在用起來(lái)更簡(jiǎn)潔高效的處理 JSON 的包。

SJSON[6](寫(xiě) JSON)和 GJSON[7](讀 JSON)是 Josh Baker[8] 開(kāi)發(fā)的兩個(gè)包,你可以用來(lái)讀寫(xiě) JSON 字符串。你可以參考 README 來(lái)獲取代碼實(shí)例 —— 下面是使用 GJSON 從 JSON 字符串中獲取嵌套的值的示例:

package main
import "github.com/tidwall/gjson"
const JSON = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
func main() {
value := gjson.Get(json, "name.last")
println(value.String())
}

類(lèi)似的,下面是使用 SJSON “設(shè)置” JSON 字符串中的值返回設(shè)置之后的字符串的示例代碼:

package main
import "github.com/tidwall/sjson"
const JSON = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
func main() {
value, _ := sjson.Set(json, "name.last", "Anderson")
println(value)
}

如果 SJSON 和 GJSON 不符合你的口味,還有一些[9]其他的[10]第三方庫(kù)[11],可以用來(lái)在 Go 程序中稍微復(fù)雜點(diǎn)地處理 JSON。

責(zé)任編輯:龐桂玉 來(lái)源: 馬哥Linux運(yùn)維
相關(guān)推薦

2024-11-04 09:02:51

Go項(xiàng)目接口

2022-07-19 08:01:55

函數(shù)Go格式化

2022-09-05 08:55:15

Go2提案語(yǔ)法

2021-09-13 07:53:31

Go錯(cuò)誤處理

2010-05-04 11:02:44

Oracle數(shù)據(jù)庫(kù)

2022-10-24 08:55:13

Go工具鏈開(kāi)發(fā)者

2020-05-06 20:40:03

Go編程語(yǔ)言

2024-04-28 11:25:02

C#JSON庫(kù)

2021-09-08 09:41:09

開(kāi)發(fā)Go代碼

2025-03-07 09:01:14

商品模塊接口項(xiàng)目

2021-01-20 16:26:17

Go編程語(yǔ)言

2024-06-24 08:10:34

Java8表達(dá)式IDE

2017-09-22 15:25:40

Go語(yǔ)言其他語(yǔ)言錯(cuò)誤處理

2009-06-22 14:26:12

ScalaXML對(duì)象

2009-02-05 17:28:01

ScalaFriendFeedXML

2014-07-22 09:01:53

SwiftJSON

2019-11-08 14:31:45

MapReduce數(shù)據(jù)集數(shù)據(jù)結(jié)構(gòu)

2023-11-06 08:01:09

Go同步異步

2023-10-26 15:49:53

Go日志

2018-07-30 13:29:04

WebAssemblyGo語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)