使用“json:”;,字符串“`返回的字符串结构标记的使用无效,正在尝试解组无引号的值

使用“json:”;,字符串“`返回的字符串结构标记的使用无效,正在尝试解组无引号的值,json,go,Json,Go,当试图解析一个json时,使用一个浮点值表示到以下结构的距离 type CreateBookingRequest struct { Distance float64 `json:"distance,string"` DistanceSource string `json:"distanceSource"` } 我得到以下错误 json:字符串struct标记的使用无效,正在尝试解组无引号的字符串 数值转换为[34

当试图解析一个json时,使用一个浮点值表示到以下结构的距离

type CreateBookingRequest struct {
    Distance          float64           `json:"distance,string"`
    DistanceSource    string            `json:"distanceSource"`
}
我得到以下错误

json:字符串struct标记的使用无效,正在尝试解组无引号的字符串 数值转换为[34 100 105 115 116 97 110 99 101 34]!(额外 *reflect.rtype=dto.CreateBookingRequest)

我有没有办法避免这个错误/得到更好的错误信息

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

当“距离”JSON值编码为数字而不是字符串时(根据“距离”字段上的“字符串”标记),会发生此错误:

如果将“距离”值的类型更改为字符串(每个标记),则其工作正常:

str := []byte(`{"distance":"1.23","distanceSource":"foo"}`)
// Note JSON string -------^
您可以通过以某种方式识别特定错误并提供不同的消息来更改错误消息。您还可以考虑更改远程类型的标记,以简单地接受数字而不是字符串:

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

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

错误只是说您使用json注释将
Distance
指定为字符串,但在json字符串中,您试图反序列化的值没有被引用(因此不是字符串)

解决方案很简单,要么将此
json:“距离,字符串”
更改为
json:“距离”
,要么获取与您的定义匹配的json(这意味着它在引号中有距离,如
“距离”:“10.4”

考虑到错误和您的原生Go类型是float64的事实,我建议删除字符串注释。

状态:

要将JSON解组到结构中,解组匹配传入对象 封送处理使用的键的键(结构字段名或其 标记),更喜欢精确匹配,但也接受不区分大小写的 匹配

因此,默认情况下,解组预期距离应为
float64
。但根据标记,您正在请求解组,以将距离作为
字符串
。以下是缺少匹配项的数据类型


因此,您有两个选项,或者使用更改距离标记,或者将距离编组为

我必须使用一个API,它有时引用数字,有时不引用。服务的所有者不太可能修复它,因此我想出了一个简单的解决方法:

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

正则表达式的效率有点低,但我不相信我能够实现更快的东西。

解决这个问题的另一种方法是使用
json.Number
。它将把所有数字数据解析为
json.Number
类型,这是一个
字符串
别名。然后你必须投下它:

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")
}

听起来您解码的JSON正文没有将距离字段作为字符串引用。您试图解组的JSON正文是什么?@Matt我已经用更多信息更新了我的问题。我会避免使用regexp。如果我必须处理这样一个JSON“类型”,我会使用
bytes.Trim
bytes.TrimFunc
、或
data=data[1:len(data)-1]
中的一个来创建自己的Go类型,具体取决于具体的需要。@DaveC你应该将其作为答案发布,它完全按照需要来做,并且尽可能地地道。除了原始问题不需要/想要接受这两种格式之外。他们只需要字符串(否则会出现可读的用户错误)。没错,我把它和golang nuts中的类似线程混淆了。那么,我会发布一个自我回答的问题:)
re := regexp.MustCompile(`(":\s*)([\d\.]+)(\s*[,}])`)
rawJsonByteArray = re.ReplaceAll(rawJsonByteArray, []byte(`$1"$2"$3`))
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")
}