简体   繁体   English

如何在Go中将调色板调配和解编为JSON?

[英]How to Marshal and Unmarshal a color palette to JSON in Go?

I want to store a custom color palette inside a JSON file, but the palette has the type []color.Color (that is an interface and not a concrete type). 我想在JSON文件中存储一个自定义调色板,但是该调色板具有[]color.Color类型(这是一个接口,而不是具体类型)。 When I marshal the palette I get something like this: 当我整理调色板时,我得到的是这样的:

[{"R":0,"G":0,"B":0,"A":255},{"R":0,"G":0,"B":51,"A":255}...]

The problem is, when I unmarshal that JSON the type []color.Color does not work, because Go cannot create a concrete type underneath that interface. 问题是,当我解组该JSON时, []color.Color类型不起作用,因为Go无法在该接口下创建具体类型。

I have simplified my code to following example: 我已将代码简化为以下示例:

type myT struct {
    P []color.Color
}

func main() {
    t := myT{palette.WebSafe}
    b, err := json.Marshal(t)
    e("json.Marshal", err)
    t2 := myT{}
    err = json.Unmarshal(b, &t2)
    e("json.Unmarshal", err)
    fmt.Println(string(b))
}

func e(s string, err error) {
    if err != nil {
        fmt.Println(s, err)
    }
}

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

Is there a simple solution or do I have to transform []color.Color to []color.RGBA ? 有没有简单的解决方案,还是我必须将[]color.Color转换为[]color.RGBA

I would follow Tim's advice and start using color.RGBA, but if you're interested in how to implement custom UnmarshalJSON functions for your custom types I've outline the code below and here: https://play.golang.org/p/8p5a09993GV 我会听从Tim的建议,并开始使用color.RGBA,但是如果您对如何为自定义类型实现自定义UnmarshalJSON函数感兴趣,请在下面和此处概述代码: https : //play.golang.org/p / 8p5a09993GV

Basically you use the UnmarshalJSON func as a middle layer to decode to the "correct" RGBA type and then do some type conversion fu to get it to become the interface you want on your custom myT type. 基本上,您将UnmarshalJSON函数用作中间层,以解码为“正确的” RGBA类型,然后进行一些类型转换,以使其成为您想要的自定义myT类型的接口。

Again, it might be easier to use color.RGBA instead of color.Color in the overall implementation, but this is HOW you would convert it if you wanted to. 同样,在整个实现中使用color.RGBA代替color.Color可能会更容易,但是如果您愿意的话,这就是如何将其转换的方法。

Here is a good gist that goes into the basics: https://gist.github.com/mdwhatcott/8dd2eef0042f7f1c0cd8 这是基础知识的好要点: https : //gist.github.com/mdwhatcott/8dd2eef0042f7f1c0cd8

A gopher academy blog post that really does some fun stuff: https://blog.gopheracademy.com/advent-2016/advanced-encoding-decoding/ Gopher学术博客文章,确实做了一些有趣的事情: https : //blog.gopheracademy.com/advent-2016/advanced-encoding-decoding/

And a good explanation on why a []struct does not 1/1 match a []interface it might implement: golang: slice of struct != slice of interface it implements? 并很好地解释了为什么[]struct与它可能实现的[]interface不匹配1/1: golang:struct的切片!=它实现的接口切片?

package main

import (
    "encoding/json"
    "fmt"
    "image/color"
    "image/color/palette"
)

type myT struct {
    P []color.Color
}

func main() {
    t := myT{palette.WebSafe}
    b, err := json.Marshal(t)
    e("json.Marshal", err)
    t2 := myT{}
    err = json.Unmarshal(b, &t2)
    e("json.Unmarshal", err)
    fmt.Println(string(b))
    fmt.Println(string(t2))
}

func e(s string, err error) {
    if err != nil {
        fmt.Println(s, err)
    }
}

func (myt *myT) UnmarshalJSON(b []byte) error {
    var tempJson struct {
        P []color.RGBA
    }
    // Unmarshal to our temp struct
    err := json.Unmarshal(b, &tempJson)
    if err != nil {
        return err
    }
    // convert our new friends O(n) to the interface type
    newColors := make([]color.Color, len(tempJson.P))
    for i, v := range tempJson.P {
        newColors[i] = color.Color(v)
    }
    myt.P = newColors
    return nil
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM