最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

重學(xué)Go語言之JSON操作詳解

 更新時間:2023年08月27日 08:25:19   作者:程序員讀書  
JSON的全稱是Javascript?Object?Notation,是一種數(shù)據(jù)結(jié)構(gòu)化交互的標(biāo)準(zhǔn)協(xié)議,這篇文章主要是來和大家介紹一下Go語言中JSON的相關(guān)操作,需要的可以參考下

當(dāng)你想在項(xiàng)目中保存配置時,你會選擇什么數(shù)據(jù)格式,你可能會說用yaml或是json,當(dāng)你作為后端要把數(shù)據(jù)返回給前端時,你會選擇什么數(shù)據(jù)格式,這次我想,一定是json了吧。

關(guān)于在Go語言如何操作JSON,在這篇文章我們來探究一下!

JSON

什么是JSON?JSON的全稱是Javascript Object Notation,是一種數(shù)據(jù)結(jié)構(gòu)化交互的標(biāo)準(zhǔn)協(xié)議,非常容易閱讀與編寫,可以作為配置文件保存應(yīng)用的相關(guān)配置信息,也可以作為前后端接口數(shù)據(jù)的格式,比如后端返回給前端這樣的JSON數(shù)據(jù):

{
	"code":404,
	"msg":"Not Found"
}

JSON的數(shù)據(jù)類型

JSON只支持六種數(shù)據(jù)類型,分別是:

  • 數(shù)字(number):有十進(jìn)制和科學(xué)記數(shù)學(xué)兩種表示方式。
  • 字符串(string):使用雙引號表示的Unicode字符序列。
  • 布爾(bool)true或者false。
  • 對象(object):使用花括號({})括起來的一個或多個鍵值對(key/value),用逗號(,)隔開,最后一個鍵值對后面不能有逗號,鍵(key)必是雙引號("")引起來的字符串,而值則可以是任意類型(如:布爾、數(shù)字、對象、數(shù)組、字符串)。
  • 數(shù)組(array):使用中括號([])括起來的值的集合,這些值可是任意類型(布爾、數(shù)字、對象、數(shù)組、字符串)。
  • null:空值。

JSON類型與Go數(shù)據(jù)類型的對應(yīng)關(guān)系:

  • Go的boolean對應(yīng)JSON的bool類型
  • Go的整型與浮點(diǎn)型對應(yīng)JSON的number類
  • Go的map和struct對應(yīng)JSON的object,map的key必須是字符串
  • Go的切片與數(shù)組對應(yīng)JSON的array
  • Go的chan與函數(shù)等復(fù)雜的類型不能作為JSON的值

JSON的基本操作

Go語言在encoding/json包中提供了JSON數(shù)據(jù)序列化與反序列化的操作,最簡單直接就是調(diào)用Marshal把一個Go的數(shù)據(jù)序列化為一個JSON數(shù)據(jù)和調(diào)用Unmarshal對JSON數(shù)據(jù)反序列化。

Marshal

json包的Marshal()函數(shù)用于將數(shù)據(jù)編碼為一個JSON文本,該函數(shù)的簽名如下所示:

func Marshal(v interface{}) ([]byte, error) 

Marshal()函數(shù)可以接受任意值,并返回JSON化的字節(jié)數(shù)組與一個error類型:

package main
import (
	"encoding/json"
	"fmt"
)
func main() {
	m := map[string]int{"Go入門": 1, "Go Ation": 2, "Go從入門到精通": 3, "Go高級編程": 4}
	data, err := json.Marshal(m)
	if err != nil {
		panic(err)
	}
    //轉(zhuǎn)換為string并輸出
	fmt.Println(string(data)) 
}

上面示例程序的運(yùn)行結(jié)果:

{"Go Ation":2,"Go從入門到精通":3,"Go入門":1,"Go高級編程":4}

MarshalIndent

上面調(diào)用Marshal函數(shù)序列化的數(shù)據(jù)輸出了一行,如果數(shù)據(jù)太長,則不利于我們閱讀,要想輸出的JSON數(shù)據(jù)格式更友好一點(diǎn),可以用MarshalIndent函數(shù),該函數(shù)簽名如下:

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

相比于Marshal函數(shù),MarshalIndent函數(shù)可以接收一個prefixindent,用于設(shè)置輸出JSON每一行的前綴和首行縮進(jìn),下面是一個使用該函數(shù)的例子:

package main
import (
	"encoding/json"
	"fmt"
)
func main() {
	m := map[string]int{"Go入門": 1, "Go Ation": 2, "Go從入門到精通": 3, "Go高級編程": 4}
    //設(shè)置prefix為空,indent為tab
	data, err := json.MarshalIndent(m, "", "\t")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
}

設(shè)置了indent參數(shù)后的運(yùn)行結(jié)果:

{
	"Go Ation": 2,
    "Go從入門到精通": 3,
    "Go入門": 1,
    "Go高級編程": 4
}

json.Unmarshal

json包的Unmarshal()函數(shù)作用與Marshal剛好相反,用于將一個JSON數(shù)據(jù)格式反序列化到一個我們定義好的Go類型變量中,該函數(shù)的簽名如下所示:

func Unmarshal(data []byte, v interface{}) error 

下面是一個反序列化的示例:

package main
import (
	"encoding/json"
	"fmt"
)
type Book struct {
	BookName string `json:"name"`
	Number   int    `json:"num"`
}
func main() {
	jsonStr := `[{"name":"Go入門","num": 1}, {"name":"Go Ation","num": 2}, {"name":"Go從入門到精通","num": 3}, {"name":"Go高級編程","num": 4}]`
	var books []Book
	err := json.Unmarshal([]byte(jsonStr), &books)
	if err != nil {
		panic(err)
	}
	fmt.Println(books)
}

上面的例子中,我們將一個JSON反序化到一個數(shù)組當(dāng)中,而該數(shù)組的元素是一個自定義的struct類型,在struct中可以通過json tag來定義json的字段名稱。

自定義序列化

如果是自定義的數(shù)據(jù)類型,我們可以實(shí)現(xiàn)Marshaler接口和Unmarshaler接口的方法,這兩個接口的定義如下:

type Unmarshaler interface {
	UnmarshalJSON([]byte) error
}
type Marshaler interface {
	MarshalJSON() ([]byte, error)
}

當(dāng)調(diào)用Marshal函數(shù)序列化時,會調(diào)用MarshalJSON()函數(shù),我們可以在該函數(shù)中自定義序列化的邏輯:

package main
import (
	"encoding/json"
	"fmt"
	"strings"
)
type Reason uint8
const (
	Unknown = iota
	Spring
	Summer
	Autumn
	Winter
)
//自定義反序列邏輯
func (r *Reason) UnmarshalJSON(b []byte) error {
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	switch strings.ToLower(s) {
	default:
		*r = Unknown
	case "spring":
		*r = Spring
	case "summer":
		*r = Summer
	case "autumn":
		*r = Autumn
	case "winter":
		*r = Winter
	}
	return nil
}
//自定義序列邏輯
func (r Reason) MarshalJSON() ([]byte, error) {
	var s string
	switch r {
	default:
		s = "unknonw"
	case Spring:
		s = "spring"
	case Summer:
		s = "summer"
	case Autumn:
		s = "autumn"
	case Winter:
		s = "winter"
	}
	return json.Marshal(s)
}
func main() {
	r := []Reason{1, 2, 3, 4}
	data, err := json.Marshal(r)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
}

上面的代碼中,Reason也實(shí)現(xiàn)了Unmarshaler接口,因此在調(diào)用Unmarshal函數(shù)反序列化時會調(diào)用UnmarshalJSON,在該方法中我們可以自定義反序列化的邏輯:

func main() {
	jsonStr := `["winter","spring","test"]`
	var r []Reason
	err := json.Unmarshal([]byte(jsonStr), &r)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
} 

Encoder與Decoder

調(diào)用Marshal只會返回一個字節(jié)數(shù)組,Unmarshal函數(shù)只能傳入一個字節(jié)數(shù)組,如果我們想將序列化的數(shù)據(jù)寫入到不同的地方(比如保存到一個文件中),或者想從不同地方讀取JSON數(shù)據(jù)(比如從一個文件讀取),那么用EncoderDecoder會更方便。

json.Encoder

NewEncoder函數(shù)可以創(chuàng)建一個Encoder結(jié)構(gòu)體,NewEncoder函數(shù)接收一個實(shí)現(xiàn)了io.Writer接口的參數(shù),在序列化后會調(diào)用io.Writer寫入數(shù)據(jù):

package main
import (
	"encoding/json"
	"os"
)
func main() {
	m := map[string]int{"Go入門": 1, "Go Ation": 2, "Go從入門到精通": 3, "Go高級編程": 4}
	file, err := os.Create("config.json")
	if err != nil {
		panic(err)
	}
    defer file.Close()
	encoder := json.NewEncoder(file)
	encoder.SetIndent("", "\t")
	err = encoder.Encode(m)
	if err != nil {
		panic(err)
	}
}

上面程序運(yùn)行后,會把JSON數(shù)據(jù)保存到當(dāng)前目錄的config.json文件當(dāng)中。

json.Decoder

NewDecoder函數(shù)可以創(chuàng)建一個Decoder結(jié)構(gòu)體,NewDecoder函數(shù)接收一個實(shí)現(xiàn)了io.Reader接口的參數(shù),也就是說Decoderio.Reader中讀取數(shù)據(jù):

package main
import (
	"encoding/json"
	"fmt"
	"os"
)
func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	var m map[string]int
	err = decoder.Decode(&m)
	if err != nil {
		panic(err)
	}
	fmt.Println(m)
}

小結(jié)

JSON是一種非常通用的數(shù)據(jù)格式,經(jīng)常被用于前后端api接口的數(shù)據(jù)通信,而Go語言在標(biāo)準(zhǔn)庫encoding/json包中為JSON數(shù)據(jù)的編碼與反編碼提供非常好的支持。

好了,相信看完這篇文章,你應(yīng)該掌握了以下幾點(diǎn)了吧:

  • 什么是JSON
  • 如何序列化與反序列化JSON數(shù)據(jù)
  • 如何自定義序列化過程
  • json.Encoder與json.Decoder的使用

到此這篇關(guān)于重學(xué)Go語言之JSON操作詳解的文章就介紹到這了,更多相關(guān)Go JSON內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言并發(fā)之Select多路選擇操作符用法詳解

    Go語言并發(fā)之Select多路選擇操作符用法詳解

    Go?語言借用多路復(fù)用的概念,提供了?select?關(guān)鍵字,用于多路監(jiān)聽多個通道,本文就來和大家聊聊Go語言中Select多路選擇操作符的具體用法,希望對大家有所幫助
    2023-06-06
  • GO項(xiàng)目實(shí)戰(zhàn)之Gorm格式化時間字段實(shí)現(xiàn)

    GO項(xiàng)目實(shí)戰(zhàn)之Gorm格式化時間字段實(shí)現(xiàn)

    GORM自帶的time.Time類型JSON默認(rèn)輸出RFC3339Nano格式的,下面這篇文章主要給大家介紹了關(guān)于GO項(xiàng)目實(shí)戰(zhàn)之Gorm格式化時間字段實(shí)現(xiàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • Go語言中的函數(shù)詳解

    Go語言中的函數(shù)詳解

    函數(shù)是基本的代碼塊,用于執(zhí)行一個任務(wù)。本文詳細(xì)講解了Go語言中的函數(shù),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Go語言中 Channel 詳解

    Go語言中 Channel 詳解

    Go 語言中的 channel 是實(shí)現(xiàn) goroutine 間無鎖通信的關(guān)鍵機(jī)制,他使得寫多線程并發(fā)程序變得簡單、靈活、觸手可得。下面就個人理解對 channel 使用過程中應(yīng)該注意的地方進(jìn)行一個簡要的總結(jié)。
    2018-10-10
  • Go語言常見錯誤接口污染解決分析

    Go語言常見錯誤接口污染解決分析

    這篇文章主要為大家介紹了Go語言常見錯誤接口污染解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Golang學(xué)習(xí)筆記(六):struct

    Golang學(xué)習(xí)筆記(六):struct

    這篇文章主要介紹了Golang學(xué)習(xí)筆記(六):struct,本文講解了struct的聲明及初始化、struct的匿名字段(繼承)、method、method繼承和重寫等內(nèi)容,需要的朋友可以參考下
    2015-05-05
  • 使用go語言實(shí)現(xiàn)查找兩個數(shù)組的異同操作

    使用go語言實(shí)現(xiàn)查找兩個數(shù)組的異同操作

    這篇文章主要介紹了使用go語言實(shí)現(xiàn)查找兩個數(shù)組的異同操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang中Map按照Value大小排序的方法實(shí)例

    Golang中Map按照Value大小排序的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Golang中Map按照Value大小排序的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • 基于Go語言實(shí)現(xiàn)一個并發(fā)端口掃描器

    基于Go語言實(shí)現(xiàn)一個并發(fā)端口掃描器

    這篇文章主要介紹了如何使用 Go 實(shí)現(xiàn)一個并發(fā)端口掃描器,通過 Goroutine 并發(fā)掃描多個端口,極大地提升端口掃描的效率,本文不僅講解了如何使用 Go 的并發(fā)特性,還涉及了如何處理超時和錯誤,保證端口掃描的健壯性和效率,需要的朋友可以參考下
    2025-08-08
  • Go項(xiàng)目中添加生成時間與版本信息的方法

    Go項(xiàng)目中添加生成時間與版本信息的方法

    本文主要介紹了Go項(xiàng)目中添加生成時間與版本信息的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04

最新評論

托克逊县| 武川县| 黑龙江省| 波密县| 横山县| 贵港市| 建始县| 汾阳市| 明光市| 龙海市| 米泉市| 巴东县| 旺苍县| 福建省| 甘洛县| 上高县| 芮城县| 上高县| 双辽市| 太仆寺旗| 巴楚县| 宣汉县| 保定市| 麦盖提县| 岗巴县| 大同县| 酉阳| 嵊泗县| 泰来县| 嘉荫县| 股票| 鄯善县| 伊吾县| 康保县| 侯马市| 子洲县| 江陵县| 乌审旗| 高碑店市| 灵武市| 安仁县|