Golang Unmarshal slice of type interface

Viewed 2705

In this example, I would be trying to load 2D scenes that contain polygons. In the code, I would have many different structs such as Circle, Square, Rectangle, Pentagon, etc.. All would share common funcs, such as Area and Perimeter. The scene itself would be stored as a slice of the interface Polygon.

Here is the code I'm using to test this:

package main

import (
    "encoding/json"
    "fmt"
    "math"
)

type Polygon interface {
    Area() float32
}

type Rectangle struct {
    Base   float32 `json:"base"`
    Height float32 `json:"height"`
    X      float32 `json:"x"`
    Y      float32 `json:"y"`
}

func (r *Rectangle) Area() float32 {
    return r.Base * r.Height
}

type Circle struct {
    Radius float32 `json:"radius"`
    X      float32 `json:"x"`
    Y      float32 `json:"y"`
}

func (c *Circle) Area() float32 {
    return c.Radius * c.Radius * math.Pi
}

func main() {
    rect := Rectangle{Base: 10, Height: 10, X: 10, Y: 10}
    circ := Circle{Radius: 10, X: 0, Y: 0}

    sliceOfPolygons := make([]Polygon, 0, 2)

    sliceOfPolygons = append(sliceOfPolygons, &rect, &circ)

    jsonData, err := json.Marshal(sliceOfPolygons)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(jsonData))

    newSlice := make([]Polygon, 0)

    err = json.Unmarshal(jsonData, &newSlice)
    if err != nil {
        panic(err)
    }
}

In this example, I setup a slice of 2 polygons, marshal it and then try to unmarshal it again. The marshal-ed string is:

[{"base":10,"height":10,"x":10,"y":10},{"radius":10,"x":0,"y":0}]

But when I try to Unmarshal it panics:

panic: json: cannot unmarshal object into Go value of type main.Polygon

If this worked it would be really useful and simple to use. I'd say that Unmarshall can't distinguish between a Rectangle and a Circle from the json string so it can't possibly know what struct to build.

Is there any way to tag the struct or tell Unmarshal how to distinguish this structs?

1 Answers
Related