外部类型问题的JSON序列化-将映射[string]接口{}项转换为int

外部类型问题的JSON序列化-将映射[string]接口{}项转换为int,json,go,marshalling,Json,Go,Marshalling,我想序列化包gonum.org/v1/gonum/mat的类型。因为我无法实现外部类型的方法,所以我创建了一个类型 type DenseEx struct { Mtx *mat.Dense } 并实现了MarshalJSON方法,如下所示 func (d DenseEx) MarshalJSON() ([]byte, error) { js := map[string]interface{}{} rows, cols := d.Mtx.Dims() js["co

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

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)
}
我无法将标记的值转换为正确的类型。我的测试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
有什么想法吗

提前谢谢

如果您检查解组的。您将发现解组中已知的数字类型是float64

要将JSON解组为接口值,解组将在接口值中存储以下内容之一:

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。应该首先将其键入assert到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)

请尝试intf.float64,enconding/json将json数字解组到的默认类型。如本文所述,map[string]接口{}{}可能看起来很方便,但请定义一个以行、列和值为字段的类型,它要简单得多。@mkopriva:谢谢您对文档的提示。它修复了它@沃尔克:这是我想避免的。因为接下来我必须定义类似的东西:类型T struct{rows int cols int values[]float},然后我将在稠密和T结构中保留冗余数据。之后,我只对致密结构进行了研究,你们不明白我的意思。您的类型DenseEx struct{Mtx mat.Dense}非常好,我从未建议对其进行丝毫更改。使用它,并像您所做的那样附加UnmarshalJSON和MarshalJSON。我的建议是,在这两个方法中,您不应该使用map[string]interface{},而应该使用类似smth的类型T struct{Rows,Cols int;Values[]float64}。在MarshalJSON中,您可以从d.Mtx.Dims和d.Mtx.At完全像您一样填充这样的T。然后用普通编码/json.Marshal序列化这个T。在UnmarshalJSON中,您可以用另一种方式进行。这确实有效,不会导致您认为它会导致的问题。真正地试试看。当然你不能把垫子放在这样一个T形的内部,但我从来没有建议过这样做。
    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)