首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将JSON字符串解编组为常量

将JSON字符串解编组为常量
EN

Stack Overflow用户
提问于 2014-02-06 17:04:04
回答 2查看 4.1K关注 0票数 7

在我的Go代码中,我有以下情况:

代码语言:javascript
复制
type Operator int
const (
    UNKNOWN  Operator = iota
    EQUALS
    CONTAINS
    BETWEEN
    DISTANCE
)

type Filter struct {
    Field string      `json:"field"`
    Operator Operator `json:"operator"`
    Values []string   `json:"values"`
}

我期望的JSON如下所示:

代码语言:javascript
复制
{
    "operator": "EQUALS",
    "field": "name",
    "values": [ "John", "Doe" ]
}

我能否创建一个映射,以便json.Unmarshal将在过滤器结构中设置正确的运算符常量?我知道解编组器接口,但我不认为它真的可以用在一个常量值上。

我真的很想将常量保留在go代码中,因为这很好地增强了类型检查和一致性。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-02-06 18:13:15

encoding/json Unmarshaler接口将与Operator类型一起工作,但它必须有一个指针作为接收方:

代码语言:javascript
复制
func (o *Operator) UnmarshalJSON(b []byte) error {
    str := strings.Trim(string(b), `"`)

    switch {
        case str == "CONTAINS":
            *o = CONTAINS

        default:
            *o = UNKNOWN
            // or return an error...
    }

    return nil
}

JSON解码器将从Operator结构中获取Filter字段的地址,并在其上调用UnmarshalJSON方法。

请注意,您可以通过将上面的encoding/TextUnmarshaler更改为UnmarshalText来实现更通用的UnmarshalText

下面是一个游乐场示例:http://play.golang.org/p/szcnC6L86u

可以说,为操作符使用字符串基类型可能更简单:http://play.golang.org/p/FCCg1NOeYw

票数 7
EN

Stack Overflow用户

发布于 2014-02-06 17:54:17

您可以将对象包装在解编组器中。例:

代码语言:javascript
复制
package main

import (
        "encoding/json"
        "fmt"
)

type Operator int

const (
        UNKNOWN Operator = iota
        EQUALS
        CONTAINS
        BETWEEN
        DISTANCE
)

type Filter struct {
        Field       string   `json:"field"`
        RawOperator string   `json:"operator"`
        Operator    Operator `json:"-"`
        Values      []string `json:"values"`
}

type FilterUnmarshaler struct {
        Filter
}

func (f *FilterUnmarshaler) UnmarshalJSON(data []byte) error {
        if err := json.Unmarshal(data, &f.Filter); err != nil {
                return err
        }
        switch f.RawOperator {
        case "UNKOWN":
                f.Operator = UNKNOWN
        case "EQUALS":
                f.Operator = EQUALS
        case "CONTAINS":
                f.Operator = CONTAINS
        case "BETWEEN":
                f.Operator = BETWEEN
        case "DISTANCE":
                f.Operator = DISTANCE
        default:
                return fmt.Errorf("Unkown operator %s", f.RawOperator)
        }
        return nil
}

func main() {
        rawJson := []byte(`
{
    "operator": "BETWEEN",
    "field": "name",
    "values": [ "John", "Doe" ]
}
`)
        val := &FilterUnmarshaler{}
        if err := json.Unmarshal(rawJson, val); err != nil {
                panic(err)
        }
        fmt.Printf("%#v\n", val)
}

不使用包装器,我就找不到如何不陷入无限递归。

这个示例展示了如何解除封送,但您很可能也希望将其应用于Marshal,以便使用整数运算符从对象中获得正确的带有运算符字符串的json。

您还可能希望创建一个映射而不是const。或者,创建一个映射并用您的const和它们的字符串等效来手动填充它。

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

https://stackoverflow.com/questions/21609363

复制
相关文章

相似问题

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