英文:
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(`(":\s*)([\d\.]+)(\s*[,}])`)
rawJsonByteArray = re.ReplaceAll(rawJsonByteArray, []byte(`$1"$2"$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")
}
英文:
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 (
"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")
}
答案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(`{"distance":1.23,"distanceSource":"foo"}`)
// Note JSON number -------^
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)
If you change the type of the distance value to a string (per the tag) then it works fine:
str := []byte(`{"distance":"1.23","distanceSource":"foo"}`)
// 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:"distance"`
...
}
...
str := []byte(`{"distance":1.23,"distanceSource":"foo"}`)
答案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:"distance,string"
to json:"distance"
or get json that matches your definition (meaning it has distince in quotes like "Distance":"10.4"
)
Given, the error and the fact that your native Go type is a float64 I would advise getting rid of the string annotation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论