Go : When will json.Unmarshal to struct return error?

huangapple go评论85阅读模式
英文:

Go : When will json.Unmarshal to struct return error?

问题

假设我有一个结构体如下:

type A struct {
  name string `json:"name"`
}

然后在主函数中我有以下代码:

var jsonString string = `{"status":false}`
var a A
err := json.Unmarshal([]byte(jsonString), &a)

显然,上述代码无论 JSON 格式是否不同,都会产生一个空的错误。在 Go 中,json.Unmarshal() 什么时候会返回错误呢?

英文:

Assume i have a struct like

type A struct{
  name string`json:"name"`
}

Then in main i have code

var jsonString string = `{"status":false}`
var a A
error := json.Unmarshal([]byte(jsonString),&a)

apparently the code above produce a nil error, regardless the json format is different. When will json.Unmarshal() return error in Go?

答案1

得分: 35

JSON解码器在源中的值与目标中的值不对应时不会报错。例如,如果源中包含字段"status",但目标中没有,这不会被视为错误。

但是,Unmarshal函数在其他情况下会返回错误。

语法错误:

type A struct {
    Name string `json:"name"`
}
data := []byte(`{"name":what?}`)
err := json.Unmarshal(data, &a)
fmt.Println(err)  // 输出字符 'w' 寻找值的开头

JSON值无法表示为目标类型:

data := []byte(`{"name":false}`)
type B struct {
    Name string `json:"name"`
}
var b B
err := json.Unmarshal(data, &b)
fmt.Println(err) // 输出无法将布尔值解组为类型为字符串的Go值

(这只是一个值无法表示为目标类型的示例,还有其他情况。)

playground示例

英文:

The JSON decoder does not report an error if values in the source do not correspond to values in the target. For example, it's not an error if the source contains the field "status", but the target does not.

The Unmarshal function does return errors in other situations.

Syntax error

type A struct {
    Name string `json:"name"`
}
data = []byte(`{"name":what?}`)
err = json.Unmarshal(data, &a)
fmt.Println(err)  // prints character 'w' looking for beginning of value

JSON value not representable by target type:

data := []byte(`{"name":false}`)
type B struct {
  Name string `json:"name"`
}
var b B
err = json.Unmarshal(data, &b)
fmt.Println(err) // prints cannot unmarshal bool into Go value of type string

(This is one example of where the value cannot be represented by target type. There are more.)

playground example

答案2

得分: 13

json.Unmarshal()返回错误时的更多示例(除了指定无效的JSON):

指定一个nilempty切片:

i := 0
err := json.Unmarshal(nil, &i)
fmt.Println(err) // JSON输入意外结束

指定一个非指针进行解组:

err = json.Unmarshal([]byte(`{"name":"a"}`), i)
fmt.Println(err) // json: Unmarshal(non-pointer int)

nil指定为目标指针:

err = json.Unmarshal([]byte(`{"name":"a"}`), nil)
fmt.Println(err) // json: Unmarshal(nil)

指定会溢出目标类型的JSON数字。引用json.Unmarshal()的文档:

如果JSON值不适合给定的目标类型,或者JSON数字溢出目标类型,Unmarshal将跳过该字段,并尽可能完成解组。如果没有遇到更严重的错误,Unmarshal将返回描述最早出现的此类错误的UnmarshalTypeError。

示例:

var j int8
err = json.Unmarshal([]byte(`1112`), &j)
fmt.Println(err) // json: 无法将数字1112解组为int8类型的Go值

或者当尝试将某些内容解析为不是RFC3339时间戳的time.Time时:

var t time.Time
err = json.Unmarshal([]byte(`"xx"`), &t)
fmt.Println(err) // 将时间"xx"解析为"2006-01-02T15:04:05Z07:00"时出错:无法解析"xx"为"2006"类型
英文:

And more examples when json.Unmarshal() returns an error (besides specifying an invalid JSON):

Specifying a nil or empty slice:

i := 0
err := json.Unmarshal(nil, &i)
fmt.Println(err) // unexpected end of JSON input

Specifying a non-pointer to unmarshal into:

err = json.Unmarshal([]byte(`{"name":"a"}`), i)
fmt.Println(err) // json: Unmarshal(non-pointer int)

Specifying nil as the target pointer:

err = json.Unmarshal([]byte(`{"name":"a"}`), nil)
fmt.Println(err) // json: Unmarshal(nil)

Specifying JSON numbers that would overflow the target type. Quoting the doc of json.Unmarshal():

> If a JSON value is not appropriate for a given target type, or if a JSON number overflows the target type, Unmarshal skips that field and completes the unmarshalling as best it can. If no more serious errors are encountered, Unmarshal returns an UnmarshalTypeError describing the earliest such error.

To demonstrate this:

var j int8
err = json.Unmarshal([]byte(`1112`), &j)
fmt.Println(err) // json: cannot unmarshal number 1112 into Go value of type int8

Or when trying to parse something as a time.Time which is not an RFC3339 timestamp:

var t time.Time
err = json.Unmarshal([]byte(`"xx"`), &t)
fmt.Println(err) // parsing time ""xx"" as ""2006-01-02T15:04:05Z07:00"": cannot parse "xx"" as "2006"

答案3

得分: 2

<!-- language: go -->

在icza的答案中,还可以在尝试将数据解组为已定义的空指针时出现错误。例如,如果您创建了一个指向特定类型的指针切片,然后尝试将数据解组为其中一个指针,就会发生这种情况。

package main

import (
	"fmt"
	"encoding/json"
)
	
type Example struct {Name string}
    
func main() {
	exs := make([]*Example, 5)
    err := json.Unmarshal([]byte(`{"name":"jane"}`), exs[0])
    fmt.Println(err)
}
// json: Unmarshal(nil *main.Example)
英文:

<!-- language: go -->

To add to icza's answer, you can also get an error if you try to Unmarshal into a typed nil pointer. This can happen if, for example, you make a slice of pointers to a particular type, then try and unmarshal into a particular one of those pointers.

package main

import (
	&quot;fmt&quot;
	&quot;encoding/json&quot;
)
	
type Example struct {Name string}
    

func main() {
	    exs := make([]*Example, 5)
        err := json.Unmarshal([]byte(`{&quot;name&quot;:&quot;jane&quot;}`), exs[0])
        fmt.Println(err)
}
// json: Unmarshal(nil *main.Example)

huangapple
  • 本文由 发表于 2015年9月22日 13:01:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/32708717.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定