中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang中JSON遇到的坑如何解決

發布時間:2023-02-27 09:55:27 來源:億速云 閱讀:114 作者:iii 欄目:開發技術

本篇內容主要講解“Golang中JSON遇到的坑如何解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Golang中JSON遇到的坑如何解決”吧!

空指針會被解析成字符串"null"

type Person struct {
	Name string
	Age  int
}

func main() {
	var p *Person
	bytes, err := json.Marshal(p)
	checkError(err)
	fmt.Printf("len:%d, result:%s\n", len(bytes), string(bytes))  // len:4, result:null
}

func checkError(err error) {
	if err != nil {
		fmt.Printf("err:%+v\n", err)
	}
}

json.Marshal一個空指針的時候,得到的結果居然是"null"字符串,我以為是""或者報錯。

還有個奇怪的坑

type Person struct {
	Name string
	Age  int
}

func main() {
	var p *Person
	s := `null`
	err := json.Unmarshal([]byte(s), &p)
	checkError(err)
	fmt.Printf("p:%+v\n", p) // p:<nil>
}

這個居然不報錯,而是得到空指針p

如果把s隨便換成其他字符串s := "abc",則報錯:invalid character 'a' looking for beginning of value,之前我理解的是null對go來說應該跟abc沒有差別,都是字符串。沒想到他們是不一樣的,下面來深究一下json.UnMarshal底層代碼。

在UnMarshal之前它有個checkValid函數

func checkValid(data []byte, scan *scanner) error {
	scan.reset()
	for _, c := range data {
		scan.bytes++
		if scan.step(scan, c) == scanError {
			return scan.err
		}
	}
	if scan.eof() == scanError {
		return scan.err
	}
	return nil
}

checkValid函數會check每一個字符,調用step函數,step初始值是stateBeginValue

// stateBeginValue is the state at the beginning of the input.
func stateBeginValue(s *scanner, c byte) int {
	if isSpace(c) {
		return scanSkipSpace
	}
	switch c {
	case '{':
		s.step = stateBeginStringOrEmpty
		return s.pushParseState(c, parseObjectKey, scanBeginObject)
	case '[':
		s.step = stateBeginValueOrEmpty
		return s.pushParseState(c, parseArrayValue, scanBeginArray)
	case '"':
		s.step = stateInString
		return scanBeginLiteral
	case '-':
		s.step = stateNeg
		return scanBeginLiteral
	case '0': // beginning of 0.123
		s.step = state0
		return scanBeginLiteral
	case 't': // beginning of true
		s.step = stateT
		return scanBeginLiteral
	case 'f': // beginning of false
		s.step = stateF
		return scanBeginLiteral
	case 'n': // beginning of null
		s.step = stateN
		return scanBeginLiteral
	}
	if '1' <= c && c <= '9' { // beginning of 1234.5
		s.step = state1
		return scanBeginLiteral
	}
	return s.error(c, "looking for beginning of value")
}

有這么一段代碼,這是處理第一個字符的,發現它對第一個字符是n有特殊處理并且設置下一個字符處理函數為stateN

// stateN is the state after reading `n`.
func stateN(s *scanner, c byte) int {
	if c == 'u' {
		s.step = stateNu
		return scanContinue
	}
	return s.error(c, "in literal null (expecting 'u')")
}

也就是下一個字符必須是u,再下一個字符處理函數為stateNu

// stateNu is the state after reading `nu`.
func stateNu(s *scanner, c byte) int {
	if c == 'l' {
		s.step = stateNul
		return scanContinue
	}
	return s.error(c, "in literal null (expecting 'l')")
}

也就是下一個字符必須是l,再下一個字符處理函數為stateNul

// stateNul is the state after reading `nul`.
func stateNul(s *scanner, c byte) int {
	if c == 'l' {
		s.step = stateEndValue
		return scanContinue
	}
	return s.error(c, "in literal null (expecting 'l')")
}

也就是下一個字符必須是l,再下一個字符處理函數為stateEndValue。

可見checkValid函數對true,false等都有特殊處理。使用時需要注意。

對于json.Marshal函數,通過調試發現它對空指針也有特殊處理

type ptrEncoder struct {
	elemEnc encoderFunc
}

func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
	if v.IsNil() {
		e.WriteString("null")
		return
	}
	if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {
		// We're a large number of nested ptrEncoder.encode calls deep;
		// start checking if we've run into a pointer cycle.
		ptr := v.Interface()
		if _, ok := e.ptrSeen[ptr]; ok {
			e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})
		}
		e.ptrSeen[ptr] = struct{}{}
		defer delete(e.ptrSeen, ptr)
	}
	pe.elemEnc(e, v.Elem(), opts)
	e.ptrLevel--
}

如果是空指針則返回字符串"null",并且不會報錯。

int類型會被解析成float64

type Person struct {
	Name string
	Age  int
}

func main() {
	p := &Person{
		Name: "text",
		Age:  18,
	}

	bytes, err := json.Marshal(p)
	checkError(err)

	pMap := make(map[string]interface{})
	err = json.Unmarshal(bytes, &pMap)
	checkError(err)
	for k, v := range pMap {
		fmt.Printf("k:%s,v:%+v, vtype:%v\n", k, v, reflect.TypeOf(v))
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Printf("err:%+v\n", err)
	}
}

結果

k:Name,v:text, vtype:string
k:Age,v:18, vtype:float64

顯然,Age類型變成了float64。會造成什么問題呢?當int大小超過6位的時候就變成了科學計數法 比如Age=1234567, 結果為

k:Name,v:text, vtype:string
k:Age,v:1.234567e+06, vtype:float64

這個時候如果直接將map更新到db,原本是int類型的字段變成了float類型,就報錯了

到此,相信大家對“Golang中JSON遇到的坑如何解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

楚雄市| 彰化县| 文成县| 宣威市| 十堰市| 涟水县| 上栗县| 开原市| 武冈市| 江西省| 奉贤区| 荣昌县| 瑞昌市| 嘉义县| 漾濞| 无极县| 封丘县| 衡阳市| 库尔勒市| 绵阳市| 肃南| 遂昌县| 嘉鱼县| 桂林市| 乡城县| 湖北省| 峡江县| 扎赉特旗| 耿马| 仁寿县| 霍山县| 临汾市| 松原市| 甘孜县| 云和县| 拉萨市| 哈尔滨市| 临夏市| 长岛县| 吉木萨尔县| 仪征市|