首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Golang型接口解编组片

Golang型接口解编组片
EN

Stack Overflow用户
提问于 2017-07-02 13:33:14
回答 1查看 2.8K关注 0票数 3

在本例中,我将尝试加载包含多边形的2D场景。在代码中,我会有许多不同的结构,如圆圈、方格、矩形、五角大楼等。所有的人都有共同的功能,如区域和周长。场景本身将作为接口多边形的一部分存储。

下面是我用来测试这个的代码:

代码语言:javascript
复制
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个多边形组成的切片,对其进行封送,然后再尝试将其解压缩。编组字符串是:

代码语言:javascript
复制
[{"base":10,"height":10,"x":10,"y":10},{"radius":10,"x":0,"y":0}]

但当我尝试Unmarshal时,它会引起恐慌:

代码语言:javascript
复制
panic: json: cannot unmarshal object into Go value of type main.Polygon

如果这有效的话,它将是非常有用和简单的使用。我想说的是,Unmarshall不能将RectangleCircle与json字符串区分开来,所以它不可能知道要构建什么结构。

有没有任何方法来标记这个结构或者告诉Unmarshal如何区分这个结构?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-02 14:33:43

用这种方法来区分json是圆圈还是矩形。在您的JSON中,没有能够检测到类型对象的结构的标识。所以让我们制定规则。

  • 矩形的基座和高度都大于0
  • 圆半径大于0

要解组JSON,通常应该有如下所示的字段。

代码语言:javascript
复制
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。

代码语言:javascript
复制
func (obj *Object) IsCircle() bool {
    return obj.Radius > 0
}

func (obj *Object) IsRectangle() bool {
    return obj.Base > 0 && obj.Height > 0
}

您可以使方法类似()来返回struct的标识。你认为最好的。最后,您应该添加To环状/ToRectangle方法。

代码语言:javascript
复制
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,
    }
}

如果您想要多边形接口的切片,您应该将这个对象的切片转换为如下所示的多边形切片。

代码语言:javascript
复制
var polygons []Polygon
for _, obj := range newSlice {
    if obj.IsCircle() {
        polygons = append(polygons, obj.ToCircle())
    } else if obj.IsRectangle() {
        polygons = append(polygons, obj.ToRectangle())
    }
}

F4GTYdA

更新

另一种方法。制作从映射接口{}转换的转换器。该转换器能够检测出结构中存在的视场。

代码语言:javascript
复制
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
    },
}

并改变信仰

代码语言:javascript
复制
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)
}

1F

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44871357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档