在Go语言中使用JSON

Encode

将一个对象编码成JSON数据,接受一个interface{}对象,返回[]byte和error:

func Marshal(v interface{}) ([]byte, error)

Marshal函数将会递归遍历整个对象,依次按成员类型对这个对象进行编码,类型转换规则如下:

bool类型 转换为JSON的Boolean 整数,浮点数等数值类型 转换为JSON的Number string 转换为JSON的字符串(带""引号) struct 转换为JSON的Object,再根据各个成员的类型递归打包 数组或切片 转换为JSON的Array []byte 会先进行base64编码然后转换为JSON字符串 map 转换为JSON的Object,key必须是string interface{} 按照内部的实际类型进行转换 nil 转为JSON的null channel,func等类型 会返回UnsupportedTypeError

[plain] view plain copy

  1. type ColorGroup struct {
  2. ID int
  3. Name string
  4. Colors []string
  5. }
  6. group := ColorGroup{
  7. ID: 1,
  8. Name: "Reds",
  9. Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
  10. }
  11. b, err := json.Marshal(group)
  12. if err != nil {
  13. fmt.Println("error:", err)
  14. }
  15. os.Stdout.Write(b)
  16. Output:
  17. {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}

Decode

将JSON数据解码

func Unmarshal(data []byte, v interface{}) error

类型转换规则和上面的规则类似

[plain] view plain copy

  1. var jsonBlob = []byte(`[
  2. {"Name": "Platypus", "Order": "Monotremata"},
  3. {"Name": "Quoll", "Order": "Dasyuromorphia"}
  4. ]`)
  5. type Animal struct {
  6. Name string
  7. Order string
  8. }
  9. var animals []Animal
  10. err := json.Unmarshal(jsonBlob, &animals)
  11. if err != nil {
  12. fmt.Println("error:", err)
  13. }
  14. fmt.Printf("%+v", animals)
  15. Output:
  16. [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

结构体

结构体必须是大写字母开头的成员才会被JSON处理到,小写字母开头的成员不会有影响。

Mashal时,结构体的成员变量名将会直接作为JSON Object的key打包成JSON;Unmashal时,会自动匹配对应的变量名进行赋值,大小写不敏感。

Unmarshal时,如果JSON中有多余的字段,会被直接抛弃掉;如果JSON缺少某个字段,则直接忽略不对结构体中变量赋值,不会报错。

[plain] view plain copy

  1. type Message struct {
  2. Name string
  3. Body string
  4. Time int64
  5. inner string
  6. }
  7. var m = Message{
  8. Name: "Alice",
  9. Body: "Hello",
  10. Time: 1294706395881547000,
  11. inner: "ok",
  12. }
  13. b := []byte(`{"nAmE":"Bob","Food":"Pickle", "inner":"changed"}`)
  14. err := json.Unmarshal(b, &m)
  15. if err != nil {
  16. fmt.Printf(err.Error())
  17. return
  18. }
  19. fmt.Printf("%v", m)
  20. Output:
  21. {Bob Hello 1294706395881547000 ok}

StructTag

如果希望手动配置结构体的成员和JSON字段的对应关系,可以在定义结构体的时候给成员打标签:

使用omitempty熟悉,如果该字段为nil或0值(数字0,字符串"",空数组[]等),则打包的JSON结果不会有这个字段。

[plain] view plain copy

  1. type Message struct {
  2. Name string `json:"msg_name"` // 对应JSON的msg_name
  3. Body string `json:"body,omitempty"` // 如果为空置则忽略字段
  4. Time int64 `json:"-"` // 直接忽略字段
  5. }
  6. var m = Message{
  7. Name: "Alice",
  8. Body: "",
  9. Time: 1294706395881547000,
  10. }
  11. data, err := json.Marshal(m)
  12. if err != nil {
  13. fmt.Printf(err.Error())
  14. return
  15. }
  16. fmt.Println(string(data))
  17. Output:
  18. {"msg_name":"Alice"}

更灵活地使用JSON

使用json.RawMessage

json.RawMessage其实就是[]byte类型的重定义。可以进行强制类型转换。

现在有这么一种场景,结构体中的其中一个字段的格式是未知的:

[plain] view plain copy

  1. type Command struct {
  2. ID int
  3. Cmd string
  4. Args *json.RawMessage
  5. }

使用json.RawMessage的话,Args字段在Unmarshal时不会被解析,直接将字节数据赋值给Args。我们可以能先解包第一层的JSON数据,然后根据Cmd的值,再确定Args的具体类型进行第二次Unmarshal。

这里要注意的是,一定要使用指针类型*json.RawMessage,否则在Args会被认为是[]byte类型,在打包时会被打包成base64编码的字符串。

使用interface{}

interface{}类型在Unmarshal时,会自动将JSON转换为对应的数据类型:

JSON的boolean 转换为bool JSON的数值 转换为float64 JSON的字符串 转换为string JSON的Array 转换为[]interface{} JSON的Object 转换为map[string]interface{} JSON的null 转换为nil

需要注意的有两个。一个是所有的JSON数值自动转换为float64类型,使用时需要再手动转换为需要的int,int64等类型。第二个是JSON的object自动转换为map[string]interface{}类型,访问时直接用JSON Object的字段名作为key进行访问。再不知道JSON数据的格式时,可以使用interface{}。

自定义类型

如果希望自己定义对象的打包解包方式,可以实现以下的接口:

[plain] view plain copy

  1. type Marshaler interface {
  2. MarshalJSON() ([]byte, error)
  3. }
  4. type Unmarshaler interface {
  5. UnmarshalJSON([]byte) error
  6. }

实现该接口的对象需要将自己的数据打包和解包。如果实现了该接口,json在打包解包时则会调用自定义的方法,不再对该对象进行其他处理。

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2017-04-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏desperate633

LintCode 单词切分题目分析

给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词。

882
来自专栏Ryan Miao

String.split()用法以及特殊分隔符注意,ps:|

转载:http://www.cnblogs.com/mingforyou/archive/2013/09/03/3299569.html 在java.lang包...

3019
来自专栏编程

使用dict和set

Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。-...

22010
来自专栏葡萄城控件技术团队

JavaScript 开发人员需要知道的简写技巧

1303
来自专栏xingoo, 一个梦想做发明家的程序员

Oozie分布式工作流——EL表达式

oozie支持使用EL(expression language)表达式。 基本的EL常量 KB MB GB TB PB 基本EL函数 string fir...

2528
来自专栏Java开发者杂谈

java如何获取一个对象的大小

When---什么时候需要知道对象的内存大小 在内存足够用的情况下我们是不需要考虑java中一个对象所占内存大小的。但当一个系统的内存有限,或者某块程序代码允许...

1.2K7
来自专栏Linux驱动

33.QT-UTF8,GBK互转

1444
来自专栏Golang语言社区

【Go 语言社区】Go学习笔记:json处理

Encode 将一个对象编码成JSON数据,接受一个interface{}对象,返回[]byte和error: func Marshal(v interfac...

63112
来自专栏逸鹏说道

Python3 与 C# 基础语法对比(List、Tuple、Dict专栏)

Python3 与 C# 基础语法对比(基础知识场):https://www.cnblogs.com/dotnetcrazy/p/9102030.html

23810
来自专栏柠檬先生

Sass 基础(五)

@if   @if 指令是一个SassScript,它可以根据条件处理样式块,如果条件为true返回一个样式块,反之   false 返回另一个样式块,在S...

2308

扫码关注云+社区