使用`json:”string”`返回无效的使用`,`string`结构标签,尝试解组未引用的值。

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

Using `json:",string"` returning invalid use of ,string struct tag, trying to unmarshal unquoted value

问题

尝试解析具有浮点值的 JSON 到以下结构体时,出现了以下错误:

type CreateBookingRequest struct {
    Distance          float64           `json:"distance,string"`
    DistanceSource    string            `json:"distanceSource"`
}

错误信息如下:

json: invalid use of ,string struct tag, trying to unmarshal unquoted value into [34 100 105 115 116 97 110 99 101 34]%!(EXTRA *reflect.rtype=dto.CreateBookingRequest)

有没有办法可以避免这个错误或者获得更好的错误信息?

编辑:
实际上,我希望 API 的用户传递一个字符串值,但如果由于某种原因他们传递了一个非字符串值,我希望能够清楚地告诉他们,而不是显示这个难以理解的错误信息。

英文:

When trying to parse a json with a float value for distance to the following struct

type CreateBookingRequest struct {
	Distance          float64           `json:"distance,string"`
	DistanceSource    string            `json:"distanceSource"`
}

I get the following error

> json: invalid use of ,string struct tag, trying to unmarshal unquoted
> value into [34 100 105 115 116 97 110 99 101 34]%!(EXTRA
> *reflect.rtype=dto.CreateBookingRequest)

Is there a way for me to avoid the error/get a better error message?

Edit:
I am actually expecting the users of the API to pass in a string value but if they for some reason pass in a non-string value, I would like to be able to tell them clearly, instead of this hard to read error message.

答案1

得分: 3

我不是一个翻译程序,但我可以帮你翻译这段代码。以下是翻译好的内容:

我不得不使用一个API,有时会引用数字,有时不会。由于服务的所有者可能不会修复它,所以我想出了一个简单的解决方法:

re := regexp.MustCompile(`(":\s*)([\d\.]+)(\s*[,}])`)
rawJsonByteArray = re.ReplaceAll(rawJsonByteArray, []byte(`$1"$2"$3`))

正则表达式在某种程度上效率较低,但我认为我无法实现更快的解决方案。

英文:

I had to work with an API which sometimes quotes numbers and sometimes doesn't. The owners of the service weren't likely to fix it, so I came up with a simple workaround:

<!-- language: golang -->

re := regexp.MustCompile(`(&quot;:\s*)([\d\.]+)(\s*[,}])`)
rawJsonByteArray = re.ReplaceAll(rawJsonByteArray, []byte(`$1&quot;$2&quot;$3`))

Regular expressions are somewhat inefficient, but I don't believe I'd be able to implement something substantially faster.

答案2

得分: 2

[func unmarshal]状态:

> 为了将JSON解组为结构体,Unmarshal将传入的对象键与Marshal使用的键进行匹配(可以是结构字段名称或其标签),优先选择精确匹配,但也接受不区分大小写的匹配。

bool,用于JSON布尔值
float64,用于JSON数字
string,用于JSON字符串
[]interface{},用于JSON数组
map[string]interface{},用于JSON对象
nil,用于JSON null

因此,unmarshal默认情况下期望Distance为float64。但根据标签,您要求unmarshal将Distance视为string。这里缺少数据类型匹配。

因此,您有两个选择,要么将distance标签更改为float64,要么将distance编组为string

英文:

func unmarshal state:

> To unmarshal JSON into a struct, Unmarshal matches incoming object
> keys to the keys used by Marshal (either the struct field name or its
> tag), preferring an exact match but also accepting a case-insensitive
> match.

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

So, unmarshal expecting Distance should be float64 by default. But as per tag, you are requesting unmarshal to except Distance as string. Here is data type missing matches.

So you have two options, either you change distance tag with float64 or marshal distance as string.

答案3

得分: 2

另一种处理这个问题的方法是使用json.Number。它会将所有的数字数据解析为json.Number类型,它是string的别名。然后你需要进行类型转换:

package main

import (
    "encoding/json"
    "fmt"
)

type x struct {
    Num json.Number `json:"price"`
}

func castToFloat64(num json.Number) (float64, error) {
    return num.Float64()
}

func main() {
    var resultHolder x
    data := `{"price":"5"}`
    jsonErr := json.Unmarshal([]byte(data), &resultHolder)
    if jsonErr != nil {
        fmt.Println(jsonErr)
    }
    convertedNum, convertErr := castToFloat64(resultHolder.Num)
    if convertErr != nil {
        fmt.Println(convertErr)
    }
    fmt.Println(convertedNum*2, resultHolder.Num+"extraString")
}

PlayGround

英文:

Another way to deal with this issue is to use json.Number. It will parse all numeric data into json.Number type, which is a string alias. Then you have to cast it:

package main

import (
    &quot;encoding/json&quot;
    &quot;fmt&quot;
)

type x struct {
    Num json.Number `json:&quot;price&quot;`
}

func castToFloat64(num json.Number) (float64, error) {
    return num.Float64()
}

func main() {
    var resultHolder x
    data := `{&quot;price&quot;:&quot;5&quot;}`
    jsonErr := json.Unmarshal([]byte(data), &amp;resultHolder)
    if jsonErr != nil {
        fmt.Println(jsonErr)
    }
    convertedNum, convertErr := castToFloat64(resultHolder.Num)
    if convertErr != nil {
        fmt.Println(convertErr)
    }
    fmt.Println(convertedNum*2, resultHolder.Num+&quot;extraString&quot;)
}

PlayGround

答案4

得分: 1

这个错误是因为"distance"的JSON值被编码为数字而不是字符串(根据"Distance"字段上的"string"标签):

str := []byte(`{"distance":1.23,"distanceSource":"foo"}`)
// 注意JSON数字 -------^
var cbr CreateBookingRequest
err := json.Unmarshal(str, &cbr)
// err => json: invalid use of ,string struct tag, trying to unmarshal unquoted value into [34 100 105 115 116 97 110 99 101 34]%(EXTRA *reflect.rtype=main.CreateBookingRequest)

如果将distance值的类型更改为字符串(根据标签),那么它就可以正常工作:

str := []byte(`{"distance":"1.23","distanceSource":"foo"}`)
// 注意JSON字符串 -------^

你可以通过识别特定的错误并提供不同的消息来更改错误信息。你还可以考虑将Distance类型的标签更改为接受数字而不是字符串:

type CreateBookingRequest struct {
  Distance       float64 `json:"distance"`
  ...
}

...
  str := []byte(`{"distance":1.23,"distanceSource":"foo"}`)
英文:

This error happens when the "distance" JSON value is encoded as a number instead of a string (per the "string" tag on the "Distance") field:

str := []byte(`{&quot;distance&quot;:1.23,&quot;distanceSource&quot;:&quot;foo&quot;}`)
// Note JSON number -------^
var cbr CreateBookingRequest
err := json.Unmarshal(str, &amp;cbr)
// err =&gt; json: invalid use of ,string struct tag, trying to unmarshal unquoted value into [34 100 105 115 116 97 110 99 101 34]%!(EXTRA *reflect.rtype=main.CreateBookingRequest)

If you change the type of the distance value to a string (per the tag) then it works fine:

str := []byte(`{&quot;distance&quot;:&quot;1.23&quot;,&quot;distanceSource&quot;:&quot;foo&quot;}`)
// Note JSON string -------^

You could change the error message by identifying that specific error somehow and provide a different message. You might also consider changing the tag for the Distance type to simply accept a number instead of a string:

type CreateBookingRequest struct {
  Distance       float64 `json:&quot;distance&quot;`
  ...
}

...
  str := []byte(`{&quot;distance&quot;:1.23,&quot;distanceSource&quot;:&quot;foo&quot;}`)

答案5

得分: 1

错误只是在告诉你,你在json注释中将Distance指定为字符串,但在json字符串中,你尝试反序列化的值没有加引号(因此不是字符串)。

解决方法很简单,要么将json:"distance,string"更改为json:"distance",要么获取与你的定义匹配的json(意味着它在引号中有"Distance":"10.4")。

考虑到错误和你的本机Go类型是float64,我建议去掉字符串注释。

英文:

The error is simply saying you designated Distance as a string with your json annotations but in the json string you're trying to deserialize the value is not quoted (therefor not a string).

The solution is simple, either change this json:&quot;distance,string&quot; to json:&quot;distance&quot; or get json that matches your definition (meaning it has distince in quotes like &quot;Distance&quot;:&quot;10.4&quot;)

Given, the error and the fact that your native Go type is a float64 I would advise getting rid of the string annotation.

huangapple
  • 本文由 发表于 2015年3月23日 23:21:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/29213974.html
匿名

发表评论

匿名网友

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

确定