json - 需要将 JSON 中的整数解析为整数,而不是 float

标签 json go

首先让我解释一下这个问题。

我的 Golang 应用程序中有一个 JSON 记录流。它基本上将这些转发到数据存储 (InfluxDB)。 JSON 中有一些整数值,也有一些浮点值。必须将这些转发到具有原始数据类型的数据存储。如果他们不这样做,就会发生类型冲突,写操作就会失败。

Ruby JSON 解析器可以毫不费力地执行此操作:

require 'json'
obj = { "a" => 123, "b" => 12.3 }
parsed = JSON.parse(obj.to_json)

print parsed["a"].class # => Integer
print parsed["b"].class # => Float

Golang 中的encoding/json 包确实有一些问题(所有数字都被解析为 float ):

package main

import "encoding/json"
import "fmt"

func main () {
  str := "{\"a\":123,\"b\":12.3}"
  var parsed map[string]interface{}
  json.Unmarshal([]byte(str), &parsed)
  for key, val := range parsed {
    switch val.(type) {
    case int:
      fmt.Println("int type: ", key)
    case float64:
      fmt.Println("float type: ", key)
    default:
      fmt.Println("unknown type: ", key)
    }
  }
}

打印:

float type:  a
float type:  b

我需要一种方法来将整数解析为整数,将 float 解析为 float ,就像 Ruby JSON 解析器所做的那样。

在这种情况下,将所有内容都解析为字符串并检查是否有小数是不可行的。某些值以字符串形式出现,例如“123”,我需要将这些值作为字符串 推送。

我没有解析对象的结构,也不是一个选项。 golang 应用程序实际上并不关心架构,只是在收到输入时转发输入。


我尝试了此处概述的方法:Other ways of verifying reflect.Type for int and float64 (使用 reflect)但它没有准确识别 int:

t := reflect.TypeOf(parsed["a"])
k := t.Kind()
k == reflect.Int // false
k == reflect.Float64 // true

最佳答案

例如,Ruby JSON 数字类型使用通用的 Go 机制来自定义 JSON 值,

package main

import (
    "encoding/json"
    "fmt"
    "strconv"
)

func main() {
    str := `{"a":123,"b":12.3,"c":"123","d":"12.3","e":true}`
    var raw map[string]json.RawMessage
    err := json.Unmarshal([]byte(str), &raw)
    if err != nil {
        panic(err)
    }
    parsed := make(map[string]interface{}, len(raw))
    for key, val := range raw {
        s := string(val)
        i, err := strconv.ParseInt(s, 10, 64)
        if err == nil {
            parsed[key] = i
            continue
        }
        f, err := strconv.ParseFloat(s, 64)
        if err == nil {
            parsed[key] = f
            continue
        }
        var v interface{}
        err = json.Unmarshal(val, &v)
        if err == nil {
            parsed[key] = v
            continue
        }
        parsed[key] = val
    }
    for key, val := range parsed {
        fmt.Printf("%T: %v %v\n", val, key, val)
    }
}

Playground :https://play.golang.org/p/VmG8IZV4CG_Y

输出:

int64: a 123 
float64: b 12.3 
string: c 123 
string: d 12.3 
bool: e true 

另一个例子,使用 Go json.Number 类型的 Ruby JSON 数字类型,

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

func main() {
    str := `{"a":123,"b":12.3,"c":"123","d":"12.3","e":true}`
    var parsed map[string]interface{}
    d := json.NewDecoder(strings.NewReader(str))
    d.UseNumber()
    err := d.Decode(&parsed)
    if err != nil {
        panic(err)
    }
    for key, val := range parsed {
        n, ok := val.(json.Number)
        if !ok {
            continue
        }
        if i, err := n.Int64(); err == nil {
            parsed[key] = i
            continue
        }
        if f, err := n.Float64(); err == nil {
            parsed[key] = f
            continue
        }
    }
    for key, val := range parsed {
        fmt.Printf("%T: %v %v\n", val, key, val)
    }
}

Playground :https://play.golang.org/p/Hk_Wb0EM-aY

输出:

int64: a 123
float64: b 12.3
string: c 123
string: d 12.3
bool: e true

@ShudiptaSharma 建议的工作版本。

关于json - 需要将 JSON 中的整数解析为整数,而不是 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53422587/

相关文章:

c# - 非 JavaScript 应用程序中的 JSON

javascript - 从 javascript 中的字符串中删除 "\"

json - 当 'Content-Type' 设置为 'application/json' 时,无法发送 post 请求

docker - 在 .dockerignore 文件中包含 pkg

c# - 从 VAT eu 解析一个 json

c# - Json.Encode()是否使用JavaScriptSerializer类序列化

http - 如何将数据返回给 channel 的发送者

go - 如果未提供证书,单元测试 tls.LoadX509KeyPair 将失败

去为 gcp compute sdk 创建一个 mock

go - 如何部署 iris(Go Web 框架)项目?