如何构造JSON,以便我可以使用golang接收int64和字符串?

时间:2018-08-20 03:37:48

标签: json go

我有以下示例代码:

type Num struct {
    X uint64 `json:"x,string"`
    Y float64 `json:"y,string"`
}

现在,如果我运行代码

js := []byte(`{"x": "123", "y": "1.23"}`)
var n Num
err := json.Unmarshal(js, &n)

它可以解析。

但是如果我将JSON更改为

js := []byte(`{"x": 123, "y": 1.23}`)

它返回一个错误。

我能理解的结果。

现在,我的问题是如何使它同时接受字符串和uint64 / float64?

2 个答案:

答案 0 :(得分:1)

您将需要定义一个实现json.Unmarshaler interface的自定义类型,以使该值可以是字符串或纯数字。

以下示例显示了如何针对单一类型(uint64)进行操作;您将需要为其他任何数字类型(Go Playground)重复该模式:

type Uint64 uint64

type Num struct {
  X Uint64 `json:"x"`
}

func (u *Uint64) UnmarshalJSON(bs []byte) error {
  str := string(bs) // Parse plain numbers directly.
  if bs[0] == '"' && bs[len(bs)-1] == '"' {
    // Unwrap the quotes from string numbers.
    str = string(bs[1 : len(bs)-1])
  }
  x, err := strconv.ParseUint(str, 10, 64)
  if err != nil {
    return err
  }
  *u = Uint64(x)
  return nil
}

func main() {
  ss := []string{`{"x":"123"}`, `{"x":123}`}
  var n Num

  for _, s := range ss {
    err := json.Unmarshal([]byte(s), &n)
    fmt.Printf("OK: s=%-11s  n=%#v  err=%v\n", s, n, err)
  }
  // OK: s={"x":"123"}  n=main.Num{X:0x7b}  err=<nil>
  // OK: s={"x":123}    n=main.Num{X:0x7b}  err=<nil>
}

答案 1 :(得分:1)

在@maerics答案的基础上,您可以将这两种情况都推迟到通常的json unmarshaler上,这感觉更强大:

package main

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

type Uint64 uint64

type Num struct {
    X Uint64 `json:"x"`
}

func (u *Uint64) UnmarshalJSON(bs []byte) error {
    var i uint64
    if err := json.Unmarshal(bs, &i); err == nil {
        *u = Uint64(i)
        return nil
    }
    var s string
    if err := json.Unmarshal(bs, &s); err != nil {
        return errors.New("expected a string or an integer")
    }
    if err := json.Unmarshal([]byte(s), &i); err != nil {
        return err
    }
    *u = Uint64(i)
    return nil
}

func main() {
    ss := []string{`{"x":"123"}`, `{"x":123}`, `{"x":0.12}`}
    var n Num

    for _, s := range ss {
        err := json.Unmarshal([]byte(s), &n)
        fmt.Printf("OK: s=%-11s  n=%#v  err=%v\n", s, n, err)
    }
}

给出

OK: s={"x":"123"}  n=main.Num{X:0x7b}  err=<nil>
OK: s={"x":123}    n=main.Num{X:0x7b}  err=<nil>
OK: s={"x":0.12}   n=main.Num{X:0x7b}  err=expected a string or an integer