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

我遇到过这样一种情况,我有一些可能是无穷大/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 的一个选项?


一只斗牛犬
浏览 147回答 2
2回答

慕田峪4524236

值的自定义处理可以通过实现接口的自定义类型来完成Marshaler。Something但是,您的类型格式不正确。它被定义为type Something interface{},而实际上应该是type Something struct:type Something struct {&nbsp; &nbsp; Id&nbsp; &nbsp; &nbsp; string&nbsp; &nbsp; `firestore:"id"`&nbsp; &nbsp; NumberA JSONFloat `firestore:"numberA"`&nbsp; &nbsp; NumberB JSONFloat `firestore:"numberB"`&nbsp; &nbsp; NumberC JSONFloat `firestore:"numberC"`}type JSONFloat float64func (j JSONFloat) MarshalJSON() ([]byte, error) {&nbsp; &nbsp; v := float64(j)&nbsp; &nbsp; if math.IsInf(j, 0) {&nbsp; &nbsp; &nbsp; &nbsp; // handle infinity, assign desired value to v&nbsp; &nbsp; &nbsp; &nbsp; // or say +/- indicates infinity&nbsp; &nbsp; &nbsp; &nbsp; s := "+"&nbsp; &nbsp; &nbsp; &nbsp; if math.IsInf(v, -1) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s = "-"&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return []byte(s), nil&nbsp; &nbsp; }&nbsp; &nbsp; return json.Marshal(v) // marshal result as standard float64}func (j *JSONFloat) UnsmarshalJSON(v []byte) error {&nbsp; &nbsp; if s := string(v); s == "+" || s == "-" {&nbsp; &nbsp; &nbsp; &nbsp; // if +/- indiciates infinity&nbsp; &nbsp; &nbsp; &nbsp; if s == "+" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *j = JSONFloat(math.Inf(1))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; *j = JSONFloat(math.Inf(-1))&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; }&nbsp; &nbsp; // just a regular float value&nbsp; &nbsp; var fv float64&nbsp; &nbsp; if err := json.Unmarshal(v, &fv); err != nil {\&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; *j = JSONFloat(fv)&nbsp; &nbsp; return nil}应该这样做

烙印99

我创建了xhhuango/json来支持 NaN、+Inf 和 -Inf。type T struct {&nbsp; &nbsp; N&nbsp; float64&nbsp; &nbsp; IP float64&nbsp; &nbsp; IN float64}func TestMarshalNaNAndInf(t *testing.T) {&nbsp; &nbsp; s := T{&nbsp; &nbsp; &nbsp; &nbsp; N:&nbsp; math.NaN(),&nbsp; &nbsp; &nbsp; &nbsp; IP: math.Inf(1),&nbsp; &nbsp; &nbsp; &nbsp; IN: math.Inf(-1),&nbsp; &nbsp; }&nbsp; &nbsp; got, err := Marshal(s)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; t.Errorf("Marshal() error: %v", err)&nbsp; &nbsp; }&nbsp; &nbsp; want := `{"N":NaN,"IP":+Inf,"IN":-Inf}`&nbsp; &nbsp; if string(got) != want {&nbsp; &nbsp; &nbsp; &nbsp; t.Errorf("Marshal() = %s, want %s", got, want)&nbsp; &nbsp; }}func TestUnmarshalNaNAndInf(t *testing.T) {&nbsp; &nbsp; data := []byte(`{"N":NaN,"IP":+Inf,"IN":-Inf}`)&nbsp; &nbsp; var s T&nbsp; &nbsp; err := Unmarshal(data, &s)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; t.Fatalf("Unmarshal: %v", err)&nbsp; &nbsp; }&nbsp; &nbsp; if !math.IsNaN(s.N) || !math.IsInf(s.IP, 1) || !math.IsInf(s.IN, -1)&nbsp; &nbsp; &nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; t.Fatalf("after Unmarshal, s.N=%f, s.IP=%f, s.IN=%f, want NaN, +Inf, -Inf", s.N, s.IP, s.IN)&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go