求助:
一个 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:0 前段时间写了个 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 ![]() 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 ![]() 用 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 ![]() Json 的数据类型是基于 js 的,所以数字类型只有 float64 ,不存在其他类型。 |
17 joyme 2023-08-31 09:58:24 +08:00 ![]() 可以定义一个 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 ![]() @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 |