在Go中解组对象数组

时间:2017-07-03 15:31:50

标签: arrays go

在GO中,我试图生成以下json:

[["my",257.14,257.24],["txt", 121.11, 65.555]]

来自一个经过解组的结构 - 而且我没有这样做。

以下是我的尝试:

x := []MyStruct{{Zero: map[int]string{0: "str"}, One: map[int]float32{1: 5.6}, Two: map[int]float32{1: 5.88}}}

MyStruct在哪里:

type Timestamp struct {
  Zero      map[int]string      `json:"0"`
  One       map[int]float32     `json:"1"`
  Two       map[int]float32     `json:"2"`
}

这会产生错误的json结构:

"myStruct":[{"0":{"0":"has"},"1":{"1":5.6},"2":{"1":5.88}}]

还尝试this

正确方向的任何线索都将受到高度赞赏。

2 个答案:

答案 0 :(得分:3)

也许这是你的期望。可以实现自定义MarshalJSON / UnmarshalJSON。

package main

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

type Timestamp struct {
    Zero []string
    One  []float32
    Two  []float32
}

func (t *Timestamp) UnmarshalJSON(b []byte) error {
    var arr [][3]interface{}
    err := json.Unmarshal(b, &arr)
    if err != nil {
        return nil
    }
    t.Zero = nil
    t.One = nil
    t.Two = nil
    for _, v := range arr {
        if len(v) != 3 {
            return errors.New("invalid json")
        }
        if s, ok := v[0].(string); ok {
            t.Zero = append(t.Zero, s)
        }
        if f, ok := v[1].(float64); ok {
            t.One = append(t.One, float32(f))
        }
        if f, ok := v[2].(float64); ok {
            t.Two = append(t.Two, float32(f))
        }
    }
    return nil
}

func (t *Timestamp) MarshalJSON() ([]byte, error) {
    var arr [][3]interface{}
    var max int
    if max < len(t.Zero) {
        max = len(t.Zero)
    }
    if max < len(t.One) {
        max = len(t.One)
    }
    if max < len(t.Two) {
        max = len(t.Two)
    }
    for i := 0; i < max; i++ {
        var v [3]interface{}
        if i < len(t.Zero) {
            v[0] = t.Zero[i]
        }
        if i < len(t.One) {
            v[1] = t.One[i]
        }
        if i < len(t.Two) {
            v[2] = t.Two[i]
        }
        arr = append(arr, v)
    }
    return json.Marshal(arr)
}

const j = `[["my",257.14,257.24],["txt", 121.11, 65.555]]`

func main() {
    var ts Timestamp
    err := json.Unmarshal([]byte(j), &ts)
    if err != nil {
        log.Fatal(err)
    }
    b, err := json.Marshal(&ts)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(b))
}

https://play.golang.org/p/WtVEja1JDY

答案 1 :(得分:2)

您遇到的问题是您正在尝试解组地图,而地图会与JSON对象相关联。您所需的输出是一个列表,因此您需要解组数组或切片以获取列表作为您的值。

尝试制作适配器。

小例子:

type Object struct {
    Base   float32 
    Radius float32 
    Height float32 
    X      float32 
    Y      float32 
}

func (obj *Object) ToCircle() *Circle {
    return &Circle{
        Radius: obj.Radius,
        X:      obj.X,
        Y:      obj.Y,
    }
}

func (obj *Object) ToRectangle() *Rectangle {
    return &Rectangle{
        Base:   obj.Base,
        Height: obj.Height,
        X:      obj.X,
        Y:      obj.Y,
    }
}

在上面的示例中,Object分别使用RectangleCircle适配器转换为ToRectangle()ToCircle()。在您的情况下,您需要将Timestamp转换为[]interface{}。然后你可以解组,你只需要得到该切片中任何值的列表,在这种情况下,这是你想要的输出。

对于intsance,签名如果您的适配器看起来像这样:

func (t *Timestamp) ToFoo() []interface{} {
    var ret []interface{}

    // Do some stuff to take values of 't' and append to 'ret'

    return ret
}

func main() {
    var result []interface{}

    json.Unmarshal(t.ToFoo(), &result)

    // ...
}

我将为您留下实施细节。