Golang JSON 的进阶用法

栏目: Go · 发布时间: 7年前

内容简介:痛点如果你有或者你想,获取你可以看看这篇文章。重现问题
Golang JSON 的进阶用法

Golang json 的进阶用法

痛点

  1. 你是否遇到过json中某个字段填入某种类型都适合而陷入两难境地? (例如:定义了一个port字段,你却不知道是填入 8080 ,还是 “8080” 的尴尬局面)

  2. 你是否遇到过json反解析报错是因为填入字段的类型不匹配导致的?例如:

    json: cannot unmarshal number into Go struct field Host.port of type string
  3. 你是否有json某字段兼容2种或者多种的数据结构的需求?

  4. 你是否想让程序更优雅,更具有适配性,而不在被这些小细节头痛?

如果你有或者你想,获取你可以看看这篇文章。

重现问题

我们给了用户一个json如下:

{
    "name":"yulibaozi",
    "port":8080
}

但是,业务方却误填了”8080”,结果我们程序反解析报错,导致业务失败。

json: cannot unmarshal number into Go struct field Host.port of type string

或许你认为这是业务方的问题,但我认为我们可以更优雅的解决这个问题。

如何解决问题

我们先定义了一个结构体

type Host struct {
    Name string `json:"name"`
    Port Port   `json:"port"`
}

心细的你会发现,Port既不是int也不是string类型,而是Port类型,而Port类型是:

type Type int

const (
    Int Type = iota
    String
)

type Port struct {
    Type   Type
    IntVal int
    StrVal string
}

在Port结构体中,我们发现了Type类型, 而Type类型包括了int,string两种类型。接下来就非常重要了,我们需要实现以下这两个接口。

json.Unmarshaller interface
json.Marshaller interface

实现代码如下:

type Port struct {
    Type   Type
    IntVal int
    StrVal string
}

// 实现 json.Unmarshaller 接口
func (port *Port) UnmarshalJSON(value []byte) error {
    if value[0] == '"' {
        port.Type = String
        return json.Unmarshal(value, &port.StrVal)
    }
    port.Type = Int
    return json.Unmarshal(value, &port.IntVal)
}

// 实现 json.Marshaller 接口
func (port Port) MarshalJSON() ([]byte, error) {
    switch port.Type {
    case Int:
        return json.Marshal(port.IntVal)
    case String:
        return json.Marshal(port.StrVal)
    default:
        return []byte{}, fmt.Errorf("impossible Port.Type")
    }
}

接下来测试:

测试反解析

  1. 测试反解析int

    给出json数据:

    {"name":"yulibaozi","port":8090}

    反解析得到的结构体数据如下:

    &{Name:yulibaozi Port:{Type:0 IntVal:8090 StrVal:}}
  2. 测试反解析string:

    给出json数据:

    {"name":"yulibaozi","port":"8090"}

    反解析得到的结构体数据如下:

    &{Name:yulibaozi Port:{Type:1 IntVal:0 StrVal:8090}}

测试编码的json

  1. 测试编码int的结构体如下:

    host := &Host{
         Name: "yulibaozi",
         Port: Port{
             Type:   Int,
             IntVal: 8080,
         },
     }

    编码后的json如下:

    {"name":"yulibaozi","port":8080}
  2. 测试编码string的结构体如下:

    host := &Host{
         Name: "yulibaozi",
         Port: Port{
             Type:   String,
             StrVal: "8080",
         },
     }

    编码后的json数据如下:

    {"name":"yulibaozi","port":"8080"}

在反编码测试中,你会发现当json填入的类型不同时,会编码到结构体中对应的字段中。

在编码测试中, 具体编码那个数据是由Type来确定的。

总结

其实,这篇文章只是分享了下json中使用的小技巧,他打破了在使用json时,需要呆板的数据结构的印象,转而走向了多变,灵活跳脱的风格,其实,这这个小tips的核心在于实现Unmarshaller,Marshaller这两个结构体,他们的实现是这个分享的关键,当然,你可以实现如开篇所说的那样,json某字段兼容2种及以上结构,当然,你也可以对yaml,toml等进行折腾,都会得到你想要的答案。

编辑:Ghoul


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Everything Store

The Everything Store

Brad Stone / Little, Brown and Company / 2013-10-22 / USD 28.00

The definitive story of Amazon.com, one of the most successful companies in the world, and of its driven, brilliant founder, Jeff Bezos. Amazon.com started off delivering books through the mail. Bu......一起来看看 《The Everything Store》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具