JSON 外部类型序列化问题 - 将 map[string]interface{} 项转换为 int

JSON Serialization of external type issue - convert map[string]interface{} item to int

我想序列化包 gonum.org/v1/gonum/mat 的类型 Dense。因为我不能为外部类型实现方法,所以我创建了一个类型

type DenseEx struct {
    Mtx *mat.Dense
}

并实现了MarshalJSON方法如下

func (d DenseEx) MarshalJSON() ([]byte, error) {
    js := map[string]interface{}{}
    rows, cols := d.Mtx.Dims()
    js["cols"] = cols
    js["rows"] = rows
    fltVals := make([]float64, cols*rows)
    for r := 0; r < rows; r++ {
       for c := 0; c < cols; c++ {
            i := r*cols + c
            fltVals[i] = d.Mtx.At(r, c)
        }
    }
  js["values"] = fltVals
  return json.Marshal(js)
}

这按预期工作。现在我遇到了解组结构的问题。

func (d DenseEx) UnmarshalJSON(data []byte) error {
    js := map[string]interface{}{}
    err := json.Unmarshal(data, &js)
    if err != nil {
        return err
    }
    intf, ok := js["cols"]
    if !ok {
        return fmt.Errorf("tag 'cols' missing in JSON data")
    }
    var cols, rows int
    cols, ok = intf.(int)
    if !ok {
        return fmt.Errorf("tag 'cols' cannot be converted to int")
    }
    ...
    return nil
}

我无法将标签的值转换为正确的类型。我的测试 json 字符串是

var jsonStrs = []struct {
    str         string
    expected    DenseEx
    description string
}{
    {
        str: "{\"cols\":3,\"rows\":2,\"values\":[6,1,5,2,4,3]}",
        expected: DenseEx{
            Mtx: nil,
        },
        description: "deserialization of a 2x3 matrice",
    },
}

我的测试代码是

...
for _, d := range jsonStrs {
    var m DenseEx
    err := m.UnmarshalJSON([]byte(d.str))
...

我总能得到结果

matex_test.go:26: FAIL: deserialization of a 2x3 matrice: tag 'cols' cannot be converted to int

有什么想法吗?

提前致谢!

如果你勾选 Unmarshal 的 docs。你会发现 Unmarshal 中 Numbers 的已知类型是 float64

为了将 JSON 解组为接口值,Unmarshal 在接口值中存储以下之一:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

因此,当您尝试解组一个 int 时,您将得到它作为 float 64。应该先将其断言为 float64 intf.(float64),然后将其转换为 int

例如:

    intf, ok := js["cols"]
    if !ok {
        return fmt.Errorf("tag 'cols' missing in JSON data")
    }
    var cols, rows int

    ucols, ok := intf.(float64)
    if !ok {
        return fmt.Errorf("tag 'cols' cannot be converted to float64")
    } 

    cols = int(ucols)