为了账号安全,请及时绑定邮箱和手机立即绑定

Go 在转换为 JSON 之前如何处理 float infinity

Go 在转换为 JSON 之前如何处理 float infinity

Go
一只斗牛犬 2023-03-07 13:27:16
我遇到过这样一种情况,我有一些可能是无穷大/NaN 的 float64 字段,并且尝试编组到 JSON 会导致有关不支持 +Inf 类型的错误。type Something interface {  Id string `firestore:"id"`  NumberA float64 `firestore:"numberA"`  NumberB float64 `firestore:"numberB"`  NumberC float64 `firestore:"numberC"`}该结构最初是通过另一个库 (Google Firestore) 填充的。实际上,这个结构要大得多,有更多的浮动字段。我想我可以使用类似下面这个循环的东西,使用反射来找到它们,尽管我想知道是否有更简洁的方法或更惯用的方法。v := reflect.ValueOf(structVar)typeOfS := v.Type()for i := 0; i< v.NumField(); i++ {  if typeOfS.Field(i).Type.Kind() == reflect.Float64 && math.IsInf(v.Field(i).Interface().(float64), 1) {    // ... some logic I'll put here  }}我不明白如何实现自定义编组,所以也许这可能是处理 +Inf 的一个选项?
查看完整描述

2 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

值的自定义处理可以通过实现接口的自定义类型来完成Marshaler。Something但是,您的类型格式不正确。它被定义为type Something interface{},而实际上应该是type Something struct:


type Something struct {

    Id      string    `firestore:"id"`

    NumberA JSONFloat `firestore:"numberA"`

    NumberB JSONFloat `firestore:"numberB"`

    NumberC JSONFloat `firestore:"numberC"`

}


type JSONFloat float64


func (j JSONFloat) MarshalJSON() ([]byte, error) {

    v := float64(j)

    if math.IsInf(j, 0) {

        // handle infinity, assign desired value to v

        // or say +/- indicates infinity

        s := "+"

        if math.IsInf(v, -1) {

            s = "-"

        }

        return []byte(s), nil

    }

    return json.Marshal(v) // marshal result as standard float64

}


func (j *JSONFloat) UnsmarshalJSON(v []byte) error {

    if s := string(v); s == "+" || s == "-" {

        // if +/- indiciates infinity

        if s == "+" {

            *j = JSONFloat(math.Inf(1))

            return nil

        }

        *j = JSONFloat(math.Inf(-1))

        return nil

    }

    // just a regular float value

    var fv float64

    if err := json.Unmarshal(v, &fv); err != nil {\

        return err

    }

    *j = JSONFloat(fv)

    return nil

}

应该这样做


查看完整回答
反对 回复 2023-03-07
?
烙印99

TA贡献1829条经验 获得超13个赞

我创建了xhhuango/json来支持 NaN、+Inf 和 -Inf。

type T struct {

    N  float64

    IP float64

    IN float64

}


func TestMarshalNaNAndInf(t *testing.T) {

    s := T{

        N:  math.NaN(),

        IP: math.Inf(1),

        IN: math.Inf(-1),

    }

    got, err := Marshal(s)

    if err != nil {

        t.Errorf("Marshal() error: %v", err)

    }

    want := `{"N":NaN,"IP":+Inf,"IN":-Inf}`

    if string(got) != want {

        t.Errorf("Marshal() = %s, want %s", got, want)

    }

}


func TestUnmarshalNaNAndInf(t *testing.T) {

    data := []byte(`{"N":NaN,"IP":+Inf,"IN":-Inf}`)

    var s T

    err := Unmarshal(data, &s)

    if err != nil {

        t.Fatalf("Unmarshal: %v", err)

    }

    if !math.IsNaN(s.N) || !math.IsInf(s.IP, 1) || !math.IsInf(s.IN, -1)     {

        t.Fatalf("after Unmarshal, s.N=%f, s.IP=%f, s.IN=%f, want NaN, +Inf, -Inf", s.N, s.IP, s.IN)

    }

}


查看完整回答
反对 回复 2023-03-07
  • 2 回答
  • 0 关注
  • 146 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信