Go 如何解析同一个字段可能是多种类型的 json - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
stevenshuang
V2EX    Go 编程语言

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

  •  
  •   stevenshuang 2023-08-30 22:13:37 +08:00 3161 次点击
    这是一个创建于 775 天前的主题,其中的信息可能已经有所发展或是发生改变。

    求助:

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

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

    25 条回复    2023-08-31 22:53:17 +08:00
    seers
        1
    seers  
       2023-08-30 22:16:31 +08:00 via Android
    interface 然后断言行吗
    stevenshuang
        2
    stevenshuang  
    OP
       2023-08-30 22:19:28 +08:00
    @seers 这样是可以的,我开始也是用 interface 然后判断类型,但是感觉略麻烦。想着是不是 go 的范型可以解决,但是目前看好像不太行
    virusdefender
        3
    virusdefender  
       2023-08-30 22:20:27 +08:00
    如果都是数字的话,声明成 float 就行?或者用 json.Number
    stevenshuang
        4
    stevenshuang  
    OP
       2023-08-30 22:31:23 +08:00
    @virusdefender 如果还包含其他类型,那么相比之下,直接用 interface 来解 json 更方便了吧,用哪个字段判断一下类型。
    stevenshuang
        5
    stevenshuang  
    OP
       2023-08-30 22:32:26 +08:00
    下面是一个结构的定义。帖子不能修改了,把定义放到这里了。

    ```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
        6
    xlsepiphone  
       2023-08-30 22:38:40 +08:0
    前段时间写了个 bencode 编解码库,.torrent 也是,tracker 字段可能是数组或者字符串,最后用 interface 解决。
    stevenshuang
        7
    stevenshuang  
    OP
       2023-08-30 22:45:18 +08:00
    @xlsepiphone 那我也还是先用 interface 吧。
    morebuff
        8
    morebuff  
       2023-08-30 23:05:27 +08:00
    golang 非常好用的 JSON 解析库,可以直接获取单个值: https://github.com/tidwall/gjson
    stevenshuang
        9
    stevenshuang  
    OP
       2023-08-30 23:28:59 +08:00
    @morebuff 感谢,我试试
    iyaozhen
        10
    iyaozhen  
       2023-08-30 23:33:17 +08:00
    先变成 map interface ,然后判断字段,再转成对应结构体

    https://github.com/mitchellh/mapstructure
    Rehtt
        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()
    lisxour
        12
    lisxour  
       2023-08-31 09:05:53 +08:00
    这种可变结果或者类型的 json 就不应该做成结构体啊,用可以动态获取的库,我觉得满屏的 interface 和在 ts 中满屏的 any 一样无法令人接受
    bv
        13
    bv  
       2023-08-31 09:13:41 +08:00
    还不如用 float64 接收,兼容 int float
    pubby
        14
    pubby  
       2023-08-31 09:46:49 +08:00   1
    用 json.Number ,尤其是会遇到大整数的场景

    用 float64 的坑是遇到大整数,即使整数在 int64 范围内也会有精度损失问题
    用 interface{} 也有问题,默认数字类型就会 decode 成 float64 ,除非 decoder 上用.UseNumber() 强制解析到 json.Number 类型
    mengzhuo
        15
    mengzhuo  
       2023-08-31 09:49:12 +08:00
    标准库可以用 json.RawMessage
    第三方库随意哈
    cheng6563
        16
    cheng6563  
       2023-08-31 09:56:53 +08:00   2
    Json 的数据类型是基于 js 的,所以数字类型只有 float64 ,不存在其他类型。
    joyme
        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
    yianing
        18
    yianing  
       2023-08-31 10:27:07 +08:00
    wuqiangroy
        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.
    wuqiangroy
        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
    }
    ```
    icyalala
        21
    icyalala  
       2023-08-31 11:48:49 +08:00   1
    @cheng6563 @wuqiangroy
    JSON 标准( RFC 8259 )对数字精度是没有限制的,可由具体实现自定义;只是说 double 类型用得更广泛,所以使用 double 会有更好的互操作性。
    darkengine
        22
    darkengine  
       2023-08-31 12:48:43 +08:00
    @stevenshuang "如果还包含其他类型"

    -------

    这种情况不应该找对方打一架吗?
    herozzm
        23
    herozzm  
       2023-08-31 12:50:05 +08:00 via iPhone
    用 gjson
    xsen
        24
    xsen  
       2023-08-31 16:07:22 +08:00
    gjson/sjson
    wqtacc
        25
    wqtacc  
       2023-08-31 22:53:17 +08:00
    不折腾,用 float64
    关于     帮助文档     助推广系统     博客     API     FAQ     Solana     2748 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 15:13 PVG 23:13 LAX 08:13 JFK 11:13
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86