在本例中,我将尝试加载包含多边形的2D场景。在代码中,我会有许多不同的结构,如圆圈、方格、矩形、五角大楼等。所有的人都有共同的功能,如区域和周长。场景本身将作为接口多边形的一部分存储。
下面是我用来测试这个的代码:
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)
}
}在本例中,我设置了一个由2个多边形组成的切片,对其进行封送,然后再尝试将其解压缩。编组字符串是:
[{"base":10,"height":10,"x":10,"y":10},{"radius":10,"x":0,"y":0}]但当我尝试Unmarshal时,它会引起恐慌:
panic: json: cannot unmarshal object into Go value of type main.Polygon如果这有效的话,它将是非常有用和简单的使用。我想说的是,Unmarshall不能将Rectangle和Circle与json字符串区分开来,所以它不可能知道要构建什么结构。
有没有任何方法来标记这个结构或者告诉Unmarshal如何区分这个结构?
发布于 2017-07-02 14:33:43
用这种方法来区分json是圆圈还是矩形。在您的JSON中,没有能够检测到类型对象的结构的标识。所以让我们制定规则。
要解组JSON,通常应该有如下所示的字段。
type Object struct {
Base float32 `json:"base,omitempty"`
Radius float32 `json:"radius,omitempty"`
Height float32 `json:"height,omitempty"`
X float32 `json:"x"`
Y float32 `json:"y"`
}此结构可以同时存储矩形或圆圈。然后,添加方法IsCircle和IsRectangle。
func (obj *Object) IsCircle() bool {
return obj.Radius > 0
}
func (obj *Object) IsRectangle() bool {
return obj.Base > 0 && obj.Height > 0
}您可以使方法类似()来返回struct的标识。你认为最好的。最后,您应该添加To环状/ToRectangle方法。
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,
}
}如果您想要多边形接口的切片,您应该将这个对象的切片转换为如下所示的多边形切片。
var polygons []Polygon
for _, obj := range newSlice {
if obj.IsCircle() {
polygons = append(polygons, obj.ToCircle())
} else if obj.IsRectangle() {
polygons = append(polygons, obj.ToRectangle())
}
}更新
另一种方法。制作从映射接口{}转换的转换器。该转换器能够检测出结构中存在的视场。
var converters = []func(map[string]interface{}) Polygon{
func(m map[string]interface{}) Polygon {
rectangle := new(Rectangle)
if base, ok := m["base"]; ok {
rectangle.Base = toFloat32(base)
} else {
return nil
}
if height, ok := m["height"]; ok {
rectangle.Height = toFloat32(height)
} else {
return nil
}
if x, ok := m["x"]; ok {
rectangle.X = toFloat32(x)
}
if y, ok := m["y"]; ok {
rectangle.Y = toFloat32(y)
}
return rectangle
},
func(m map[string]interface{}) Polygon {
circle := new(Circle)
if radius, ok := m["radius"]; ok {
circle.Radius = toFloat32(radius)
} else {
return nil
}
if x, ok := m["x"]; ok {
circle.X = toFloat32(x)
}
if y, ok := m["y"]; ok {
circle.Y = toFloat32(y)
}
return circle
},
}并改变信仰
var polygons []Polygon
for _, obj := range newSlice {
m, ok := obj.(map[string]interface{})
if !ok {
panic("invalid struct")
}
var p Polygon
for _, converter := range converters {
p = converter(m)
if p != nil {
break
}
}
if p == nil {
panic("unknown polygon")
}
polygons = append(polygons, p)
}https://stackoverflow.com/questions/44871357
复制相似问题