Go:将 JSON 字符串转换为 map[string] 接口{}

问题描述 投票:0回答:3

我正在尝试使用

map[string]interface{}
类型在 Go 中创建 JSON 表示。我正在处理 JSON 字符串,并且很难弄清楚如何避免 JSON 解组器自动将数字处理为 float64。结果出现以下错误。

例如。

"{ 'a' : 9223372036854775807}"
应该是
map[string]interface{} = [a 9223372036854775807
但实际上是
map[string]interface{} = [a 9.2233720368547758088E18]

我搜索了如何使用结构来通过使用

json.Number
来避免这种情况,但我真的更喜欢使用上面指定的
map
类型。

json go
3个回答
4
投票

go

json.Unmarshal(...)
函数自动使用 float64 作为 JSON 数字。如果您想将数字解组为不同的类型,那么您必须使用自定义类型和自定义解组器。无法强制解组器将自定义值反序列化为通用映射。

例如,以下是如何将“a”属性的值解析为

big.Int

package main

import (
  "encoding/json"
  "fmt"
  "math/big"
)

type MyDoc struct {
  A BigA `json:"a"`
}

type BigA struct{ *big.Int }

func (a BigA) UnmarshalJSON(bs []byte) error {
  _, ok := a.SetString(string(bs), 10)
  if !ok {
    return fmt.Errorf("invalid integer %s", bs)
  }
  return nil
}

func main() {
  jsonstr := `{"a":9223372036854775807}`
  mydoc := MyDoc{A: BigA{new(big.Int)}}

  err := json.Unmarshal([]byte(jsonstr), &mydoc)
  if err != nil {
    panic(err)
  }

  fmt.Printf("OK: mydoc=%#v\n", mydoc)
  // OK: mydoc=main.MyDoc{A:9223372036854775807}
}

1
投票
func jsonToMap(jsonStr string) map[string]interface{} {
    result := make(map[string]interface{})
    json.Unmarshal([]byte(jsonStr), &result)
    return result
}

0
投票

@maerics 接受的答案不提供OP所需的地图输出,而是一个结构。虽然这似乎是 golang 中公认的标准方法,但结构比映射更加严格,如果 JSON 和结构完全不同步,就会破坏代码。虽然它可能使 go 代码对于 golang 执行 JSON<->struct 更具确定性和“稳定”,但它却使灵活性变得痛苦。

我也想要一个通用映射来捕获所有输入,无论 JSON 的字段是什么并且无需先验知识。制作结构需要我事先了解有关 JSON 的所有信息。对于某些用例来说,这是一个缺陷。

@Omkesh Sajjanwar 的第二个答案确实实现了这一点,但仅适用于单层/非嵌套 JSON 结构。第一层键被提取并放入映射中,但所有字段都作为接口进来,如果该字段是可接口值(int、bool、float 等),那么这很好,但如果该字段是映射,则不起作用或字符串(以我对 golang 的天真的理解)。如果 func jsonToMap(jsonStr string) map[string]interface{} 可以递归地处理嵌套映射并转换字符串,那么这将是OP问题的首选和真实答案。

[如果可以的话,我会否决已接受的答案,并对这两个答案发表评论,但可惜的是,永远被 SE 声誉所阻止。我可能会因为偏离主题或太愚蠢或一些废话而被否决。非常期待。]

© www.soinside.com 2019 - 2024. All rights reserved.