使用`json:“,string“`返回无效使用,string struct标签,试图解组未引用的值

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.

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

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.

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.

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:

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.