Go 如何解析同一个字段可能是多种类型的 json

253 天前
 stevenshuang

求助:

一个 python 的服务端返回 json 数据,但是有一个字段可能是 int ,也可能是 float 。 那么 go(1.21) 该如何处理这种情况呢?

我想的是 利用 go 的范型一字段可以设置多种情况,但是实际用的时候,还是需要明确结构字段的类型。 或者就是直接用 map[string]any?

2266 次点击
所在节点    Go 编程语言
25 条回复
seers
253 天前
interface 然后断言行吗
stevenshuang
253 天前
@seers 这样是可以的,我开始也是用 interface 然后判断类型,但是感觉略麻烦。想着是不是 go 的范型可以解决,但是目前看好像不太行😅
virusdefender
253 天前
如果都是数字的话,声明成 float 就行?或者用 json.Number
stevenshuang
253 天前
@virusdefender 如果还包含其他类型,那么相比之下,直接用 interface 来解 json 更方便了吧,用哪个字段判断一下类型。
stevenshuang
253 天前
下面是一个结构的定义。帖子不能修改了,把定义放到这里了。

```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"`
}
```
xlsepiphone
253 天前
前段时间写了个 bencode 编解码库,.torrent 也是,tracker 字段可能是数组或者字符串,最后用 interface 解决。
stevenshuang
253 天前
@xlsepiphone 那我也还是先用 interface 吧。
morebuff
253 天前
golang 非常好用的 JSON 解析库,可以直接获取单个值: https://github.com/tidwall/gjson
stevenshuang
253 天前
@morebuff 感谢,我试试😁
iyaozhen
253 天前
先变成 map interface ,然后判断字段,再转成对应结构体

https://github.com/mitchellh/mapstructure
Rehtt
253 天前
https://github.com/json-iterator/go

jsoniter.Get([]byte(`{"a": 123,"b": {"c": "cc"}}`),"b").Get("c").ToString()
lisxour
253 天前
这种可变结果或者类型的 json 就不应该做成结构体啊,用可以动态获取的库,我觉得满屏的 interface 和在 ts 中满屏的 any 一样无法令人接受
bv
253 天前
还不如用 float64 接收,兼容 int float
pubby
253 天前
用 json.Number ,尤其是会遇到大整数的场景

用 float64 的坑是遇到大整数,即使整数在 int64 范围内也会有精度损失问题
用 interface{} 也有问题,默认数字类型就会 decode 成 float64 ,除非 decoder 上用.UseNumber() 强制解析到 json.Number 类型
mengzhuo
253 天前
标准库可以用 json.RawMessage
第三方库随意哈
cheng6563
253 天前
Json 的数据类型是基于 js 的,所以数字类型只有 float64 ,不存在其他类型。
joyme
253 天前
可以定义一个 struct 来代表不同的类型,然后为这个 struct 实现 Marshal/ Unmarshal 。这样这个 struct 就能代表不同的类型,使用的时候也很方便。

比如 kubernetes 里就有类似的实现。https://pkg.go.dev/k8s.io/apimachinery/pkg/util/intstr#IntOrString
yianing
253 天前
wuqiangroy
253 天前
The core issue is how to convert float64 to int.
All the numbers in a JSON string are the type of float64.
wuqiangroy
253 天前
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
}
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/969605

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX