求助:
一个 python 的服务端返回 json 数据,但是有一个字段可能是 int ,也可能是 float 。 那么 go(1.21) 该如何处理这种情况呢?
我想的是 利用 go 的范型一字段可以设置多种情况,但是实际用的时候,还是需要明确结构字段的类型。 或者就是直接用 map[string]any?
1
seers 2023-08-30 22:16:31 +08:00 via Android
interface 然后断言行吗
|
2
stevenshuang OP @seers 这样是可以的,我开始也是用 interface 然后判断类型,但是感觉略麻烦。想着是不是 go 的范型可以解决,但是目前看好像不太行😅
|
3
virusdefender 2023-08-30 22:20:27 +08:00
如果都是数字的话,声明成 float 就行?或者用 json.Number
|
4
stevenshuang OP @virusdefender 如果还包含其他类型,那么相比之下,直接用 interface 来解 json 更方便了吧,用哪个字段判断一下类型。
|
5
stevenshuang OP 下面是一个结构的定义。帖子不能修改了,把定义放到这里了。
```go type ( MetadataType interface { ~string | ~int | ~float64 | ~bool } Embedding interface { ~float64 | ~int } ) type Metadata[M MetadataType] map[string]M type GetResult[M MetadataType, E Embedding] struct { IDs []string `json:"ids"` Embeddings []E `json:"embeddings,omitempty"` Documents []string `json:"documents,omitempty"` Metadatas []Metadata[M] `json:"metadatas,omitempty"` } ``` |
6
xlsepiphone 2023-08-30 22:38:40 +08:00
前段时间写了个 bencode 编解码库,.torrent 也是,tracker 字段可能是数组或者字符串,最后用 interface 解决。
|
7
stevenshuang OP @xlsepiphone 那我也还是先用 interface 吧。
|
8
morebuff 2023-08-30 23:05:27 +08:00
golang 非常好用的 JSON 解析库,可以直接获取单个值: https://github.com/tidwall/gjson
|
9
stevenshuang OP @morebuff 感谢,我试试😁
|
10
iyaozhen 2023-08-30 23:33:17 +08:00
|
11
Rehtt 2023-08-31 08:32:32 +08:00 1
https://github.com/json-iterator/go
jsoniter.Get([]byte(`{"a": 123,"b": {"c": "cc"}}`),"b").Get("c").ToString() |
12
lisxour 2023-08-31 09:05:53 +08:00
这种可变结果或者类型的 json 就不应该做成结构体啊,用可以动态获取的库,我觉得满屏的 interface 和在 ts 中满屏的 any 一样无法令人接受
|
13
bv 2023-08-31 09:13:41 +08:00
还不如用 float64 接收,兼容 int float
|
14
pubby 2023-08-31 09:46:49 +08:00 1
用 json.Number ,尤其是会遇到大整数的场景
用 float64 的坑是遇到大整数,即使整数在 int64 范围内也会有精度损失问题 用 interface{} 也有问题,默认数字类型就会 decode 成 float64 ,除非 decoder 上用.UseNumber() 强制解析到 json.Number 类型 |
15
mengzhuo 2023-08-31 09:49:12 +08:00
标准库可以用 json.RawMessage
第三方库随意哈 |
16
cheng6563 2023-08-31 09:56:53 +08:00 2
Json 的数据类型是基于 js 的,所以数字类型只有 float64 ,不存在其他类型。
|
17
joyme 2023-08-31 09:58:24 +08:00 1
可以定义一个 struct 来代表不同的类型,然后为这个 struct 实现 Marshal/ Unmarshal 。这样这个 struct 就能代表不同的类型,使用的时候也很方便。
比如 kubernetes 里就有类似的实现。https://pkg.go.dev/k8s.io/apimachinery/pkg/util/intstr#IntOrString |
18
yianing 2023-08-31 10:27:07 +08:00
推荐 gjson https://github.com/tidwall/gjson
|
19
wuqiangroy 2023-08-31 11:38:12 +08:00
The core issue is how to convert float64 to int.
All the numbers in a JSON string are the type of float64. |
20
wuqiangroy 2023-08-31 11:45:58 +08:00
I provide a suggestion.
```golang type Res struct { Value any `json:"value"` // Int or Float FloatValue float64 IntValue int } func (r *Res) UnmarshalJSON(source []byte) (err error) { // json.number is type of float64 type Temp struct { Value float64 `json:"value"` } var temp = Temp{} decoder := json.NewDecoder(bytes.NewReader(source)) //means that number convert to json.Number decoder.UseNumber() //decode json if err = decoder.Decode(&temp); err != nil { return err } var convertToInt bool var convertValue int // convert float64 to int if convertToInt { r.IntValue = convertValue } else { r.FloatValue = temp.Value } return } ``` usage: ```golang func Usage() { var source = []byte(`{"value":123}`) var res Res _ = json.Unmarshal(source, &res) // use intValue res.IntValue // use floatValue source = []byte(`{"value":123.23}`) _ = json.Unmarshal(source, &res) res.FloatValue } ``` |
21
icyalala 2023-08-31 11:48:49 +08:00 1
@cheng6563 @wuqiangroy
JSON 标准( RFC 8259 )对数字精度是没有限制的,可由具体实现自定义;只是说 double 类型用得更广泛,所以使用 double 会有更好的互操作性。 |
22
darkengine 2023-08-31 12:48:43 +08:00
|
23
herozzm 2023-08-31 12:50:05 +08:00 via iPhone
用 gjson
|
24
xsen 2023-08-31 16:07:22 +08:00
gjson/sjson
|
25
wqtacc 2023-08-31 22:53:17 +08:00
不折腾,用 float64
|