Go语言学习笔记(二十)

  • 一、处理JSON
    • 1 JSON简介
    • 2 使用JSON API
    • 3 在Go语言中使用JSON
    • 4 解码JSON
    • 5 映射数据类型
    • 6 处理通过HTTP收到的JSON
    • 7 相关问答
      • 7.1 为编码和解码JSON,必须创建结构体,还是会自动生成结构体?
      • 7.2 为何所有人都选择使用JSON,而不是其他数据传输格式(如XML)?
      • 7.3 encoding/json包提供了验证数据有效性的途径么?
      • 7.4 必须将JSON对象中的所有数据字段都解码到结构体中么?

一、处理JSON

1 JSON简介

JavaScript对象表示法(JavaScript Object Notation,JSON)是一种用于存储和交换数据的格式,这是一种人们能够理解的纯文本格式。JSON可以键值对的方式表示数据,也可以数组的方式表示数据。JSON已成为互联网上村粗he交换数据的事实标准,从很大程度上来说它已取代可拓展的标记语言(Extensible Markup Language。XML)。虽然很多现代服务依旧提供XML格式,但JSON已经是互联网上最常见的数据格式。

虽然Go语言也支持数组,但更常见的是使用切片来表示一组元素。在其它语言中,数组也被称为列表。

JSON得以流行是因为它是一种人类能够看懂的灵活而轻量级的数据格式。虽然XML提供了模式(严格的数据表示方式),但程序员完全可以随心所欲地表示数据。从表示数据所需要的字节数上说,JSON通常更为轻量级。通过诸如互联网等网络发送数据时,可能意味着应用程序的运行速度稍快。另外,JavaScript是占统治地位的Web浏览器编程环境,而JSON是JavaScript的一个子集,因此编码和解码JSON数据就是小菜一碟。

2 使用JSON API

API(应用程序接口(API:Application Program Interface))让程序员无须直接连接到数据库,就可以请求各种格式的数据并使用他们。这样的API包括以下几个:

1.纽约市交通局:通过网络提供火车、汽车和地铁交通信息,以及自动扶梯状态信息
2.英国广播公司:提供电视和广播节目播放时间表、分类细节和图片
3.Github:提供有关github.com中各种数据的信息,包括用户、组织仓库、提交和问题
4.Dark Sky:这是一个天气预报服务,通常比其他天气预报服务更准确

3 在Go语言中使用JSON

Go标准库提供了encoding/json包,可用于编码和解码JSON数据。
编码意味着将数据转换为编码后的格式,就本章而言,设施JSON格式。encoding/json包提供了函数Marshal,可用于将GO数据编码为JSON,下面显示了一个包含一些Go数据的结构体。

package mainimport "fmt"type Person struct {Name    stringAge     intHobbies []string
}func main() {hobbies := []string{"Cycling", "Cheese", "Techno"}p := Person{Name:    "George",Age:     40,Hobbies: hobbies,}fmt.Printf("%+v\n", p)
}

运行结果如下:

接下来我们尝试使用Marshal函数将其编码为JSON格式

package mainimport ("encoding/json""fmt""log"
)type Person struct {Name    stringAge     intHobbies []string
}func main() {hobbies := []string{"Cycling", "Cheese", "Techno"}p := Person{Name:    "George",Age:     40,Hobbies: hobbies,}fmt.Printf("%+v\n", p)//这个函数的参数是一个接口,返回值是一个字节串//结构体实现了接口,因此将其作为参数直接传递给函数MarshaljsonByteData, err := json.Marshal(p)if err != nil {log.Fatal(err)}//将生成的字节切片转换为字符串,并将其打印出来jsonStringData := string(jsonByteData)fmt.Println(jsonStringData)
}

结果如下:

存在的问题:

  • 在上面例子中JSON数据中,所有的键名都以大写字母打头。但是JSON约定使用骆驼拼写法。Go语言通过给数据字段指定标签,对于JSON数据,将使用便签中的数据替换它。如下:
package mainimport ("encoding/json""fmt""log"
)type Person struct {Name    string   `json:"name"`Age     int      `json:"age"`Hobbies []string `json:"hobbies"`
}func main() {hobbies := []string{"Cycling", "Cheese", "Techno"}p := Person{Name:    "George",Age:     40,Hobbies: hobbies,}fmt.Printf("%+v\n", p)jsonByteData, err := json.Marshal(p)if err != nil {log.Fatal(err)}jsonStringData := string(jsonByteData)fmt.Println(jsonStringData)
}

结果如下:

结构体标签还可以用于指定在编码为JSON时忽略结构体中的空字段。默认情况下,如果结构体的字段被设为空值,则编码为JSON格式后,将包含Go语言零值规则指定的值

p := Person{}
{"name":"","age":0,"hobbies":null}

忽视零值,可在JSON键名后面加上omitempty

type Person struct{Name  string   `json:"name,omitempty"`Age   int      `json:"age,omitempty"`Hobbies []string `json:"hobbies,omitempty"`
}

详细示例如下:

package mainimport ("encoding/json""fmt""log"
)type Person struct {Name    string   `json:"name,omitempty"`Age     int      `json:"age,omitempty"`Hobbies []string `json:"hobbies,omitempty"`
}func main() {p := Person{}jsonByteData, err := json.Marshal(p)if err != nil {log.Fatal(err)}jsonStringData := string(jsonByteData)fmt.Println(jsonStringData)
}

运行结果如下(前者为添加omitempty,后者没有添加):

4 解码JSON

Go语言的Unmarshal函数提供了解码功能,它接收一个字节切片以及一个指定要将数据解码为何种格式的接口。根据数据是如何收到的,他可能是字节切片,也可能不是。入股不是字节切片,就必须先进行转换,再将其传递给函数Unmarshal

var jsonStringData := {"name":"George","age":40,"hobbies":["Cycling","Cheese","Techno"]}
jsonByteData := []byte(jsonStringData)

与将数据编码为JSON格式一样,必须定义一个接口,以指定要将数据解码为何种格式。与将数据编码为JSON格式一样,可使用结构体标签来告诉解码器要如何将键映射到字段。

type Person struct {Name    string   `json:"name"`Age     int      `json:"age"`Hobbies []string `json:"hobbies"`
}

详细示例如下:

package main
import ("encoding/json""fmt""log"
)
type Person struct {Name    string   `json:"name"`Age     int      `json:"age"`Hobbies []string `json:"hobbies"`
}
func main() {jsonStringData := `{"name":"George","age":40,"hobbies":["Cycling","Cheese","Techno"]}`jsonByteData := []byte(jsonStringData)p := Person{}err := json.Unmarshal(jsonByteData, &p)if err != nil {log.Fatal(err)}fmt.Printf("%+v\n", p)
}

结果如下:

5 映射数据类型

编码和解码JSON时必须考虑Go和JavaScript表示数据类型的方式,我们都知道Go是一种强类型语言,而JavaScript是一种弱类型语言,即不显示的声明变量的数据类型。下面比较了Go和JavaScript中声明字符串和整型变量的方式

//JavaScript
var i=4;
var s="string";//Go
var i int = 4
var s string = "string"

Go语言显式的声明了变量的数据类型,而JavaScript没有。由于JSON是一个JavaScript子集,因此他采用的方法和JavaScript相同:无须声明数据类型。JSON可使用的数据类型如下:

Boolean
Number
String
Array
Object
Null

JSON的数据类型不会西东映射到Go语言中的数据类型,因此encoding/json包执行显式的数据类型转换。下表显示了JSON数据类型和Go数据类型之间的对应关系。

如果在编码解码时数据类型不匹配将报错:如下

package mainimport ("encoding/json""fmt""log"
)type Switch struct {On bool `json:"on"`
}func main() {jsonStringData := `{"on":"true"}`jsonByteData := []byte(jsonStringData)s := Switch{}err := json.Unmarshal(jsonByteData, &s)if err != nil {log.Fatal(err)}fmt.Printf("%+v\n", s)
}


在这里,json中的"on"对应的值"true"是一个字符串类型

6 处理通过HTTP收到的JSON

在Go语言中,通过HTTP请求获取JSON时,收到的数据为流而不是字符串或字节切片。在这种情况下,应使用encoding/json包中的另一个方法。在这个实例中将使用Github API,这是一个很好用的API,因为它提供了格式良好的JSON,对于有些断点还无须验证身份。

res,err := http.Get("https://api.github.com/users/shapeshed")
if err != nil{log.Fatal(err)
}
defer res.Body.Close()

由于获取的数据为流,因此可使用encoding/json包中的函数NewDecoder。这个函数接收一个io.Reader(这正是http.Get返回的类型),并返回一个Decoder。通过对返回的Decoder调用方法Decode,可将数据解码为结构体。Decode也接收一个结构体,因此必须创建一个结构体实例,并将其作为参数传递给Decode。详细使用实例如下:

package mainimport ("encoding/json""fmt""log""net/http"
)type User struct {Name string `json:"name"`Blog string `json:"blog"`
}func main() {var u Userres, err := http.Get("https://api.github.com/users/shapeshed")if err != nil {log.Fatal(err)}defer res.Body.Close()err = json.NewDecoder(res.Body).Decode(&u)if err != nil {log.Fatal(err)}fmt.Printf("%+v\n", u)
}

7 相关问答

7.1 为编码和解码JSON,必须创建结构体,还是会自动生成结构体?

是的,要编码或解码JSON,必须创建结构体,虽然这样好像很繁琐,在JSON对象很大时尤其如此,但正如在前面的Github实例中看到的,这样可以让代码更健壮、容错能力更强。如果我们能将JSON类型映射到Go类型,就能将JSON用作数据交换格式,还可获得类型安全这样的好处。网上有多个服务可根据JSON数据自动创建Go结构

7.2 为何所有人都选择使用JSON,而不是其他数据传输格式(如XML)?

JSON是一种灵活、易学且富有表达力的数据格式。作为Web语言的JavaScript的崛起意味着在浏览器中使用JSON服务的确是很容易的。另外,JSON比其他格式占用的空间更少,这意味着可高效地传输和存储这种数据。

7.3 encoding/json包提供了验证数据有效性的途径么?

没有,encoding/json没有提供验证功能。我们可为计网构体编写用来验证数据的方法,但编码器没有这样的方法。有多个第三方结构体验证库。

7.4 必须将JSON对象中的所有数据字段都解码到结构体中么?

不是这样的,可定义只包含我们感兴趣的字段的结构体。我们可使用结构体标签来将JSON字段映射到Go结构体字段。

参考书籍[1]: 【Go语言入门经典】[英] 乔治·奥尔波 著 张海燕 译

Go语言学习笔记(二十)相关推荐

  1. 嵌入式系统设计师学习笔记二十八:嵌入式程序设计③——高级程序设计语言

    嵌入式系统设计师学习笔记二十八:嵌入式程序设计③--高级程序设计语言 解释程序和编译程序 编译器的工作阶段示意图 语法错误:非法字符,关键字或标识符拼写错误 语法错误:语法结构出错,if--endif ...

  2. 计算机二级C语言学习笔记(十八)

    上一篇:计算机二级C语言学习笔记(十七) 程序填空题(二) 题型二:平均值 首先求和,然后将和除以项数 ===================================== ========== ...

  3. C语言学习笔记第十天

    C语言学习笔记第十天 目录 C语言学习笔记第十天 一.什么是堆内存 二.为什么要使用堆内存 三.如何使用堆内存 四.malloc的内存管理机制 五.使用堆内存需要注意的问题 六.内存清理函数 七.堆内 ...

  4. Mr.J-- jQuery学习笔记(二十八)--DOM操作方法(添加方法总结)

    Table of Contents appendTo appendTo(source, target) 源代码 append prependTo ​ ​ ​ ​ prependTo源码 prepend ...

  5. uniapp 学习笔记二十二 购物车页面结构搭建

    uniapp 学习笔记二十二 购物车页面结构搭建 cart.vue <template><view><view class="flex padding" ...

  6. Polyworks脚本开发学习笔记(二十)-补充几个常见操作指令的使用

    Polyworks脚本开发学习笔记(二十)-补充几个常见操作指令的使用 大概要写到结尾了,最后几篇就将手册的各常用命令再看一遍,组合一下,并列举出常见的一些有用的操作. DATA_COLOR_MAP数 ...

  7. C语言学习笔记(十九)

    C语言学习第十九天. 2.10 赋值运算符与表达式 在赋值表达式中,如果表达式左边的变量重复出现在表达式的右边,如: i = i + 2; 则可以将这种表达式缩写为下列形式: i += 2; 其中的运 ...

  8. C 语言学习笔记(二):编程基础

    目录 一.冯诺依曼模型 二.程序语言发展历史 三.进制 3.1 二进制 3.2 八进制 3.3 十六进制 3.4 进制转换:二进制.八进制.十六进制.十进制之间的转换 3.4.1 将二进制.八进制.十 ...

  9. C语言学习笔记(十五)

    C语言学习第十五天 2.7 类型转换 当一个运算符的几个操作 数类型不同时,就需要通过一些规则把它们转换为某种共同的类型.一般来说,自动转换时指把"比较窄的"操作数转换为" ...

  10. JVM 学习笔记二十六、JVM监控及诊断工具-GUI篇

    二十六.JVM监控及诊断工具-GUI篇 1.工具概述 使用上一张命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但他们存在下列局限: (1)无法获取方法级别的分析数据,如方法间的调用关系 ...

最新文章

  1. 整理了一下SQL Server里面可能经常会用到的日期格式转换方法
  2. Collections 类
  3. 用U盘安装VMware ESXi4
  4. 如何在Eclipse中构建APK文件?
  5. CentOS 7.2 安装教程
  6. python使用get和post方法_python爬虫中get和post方法介绍以及cookie作用
  7. android开发之Glide加载图片之url转bitmap的方法
  8. (三十一)web 开发基础项目
  9. 华为双 11 发 20 亿奖金!?
  10. 有哪些神预言的科幻电影
  11. 20200606:最长连续序列(leetcode128)
  12. [物理学与PDEs]第2章第4节 激波 4.2 熵条件
  13. 【追一科技】NLG技术:文本生成技术多样化应用的探索之路
  14. 隐藏activity的头部的activity名
  15. UG二次开发GRIP标准件库
  16. 大数据预测(大数据核心应用)
  17. ES stored fields作用
  18. 时间序列预测方法最全总结!
  19. 跑分超小米10,“性能旗舰”iQOO 3 5G未发先火!
  20. 计算机维修分为那两种,计算机二级维修中最常见的三种方法是什么?

热门文章

  1. 中国学生校服到了改变的时候——《关于校服》心得
  2. Django学习记录3-2——Mysql数据库的使用
  3. oracle dblink 文件,oracle DBLink
  4. 使用Google 相册API
  5. Android开发环境搭建【超详细-Android初学者入门必看】
  6. Ogre 材质与材质脚本
  7. window.open在打开pdf时直接下载而不是查看
  8. ai人工智能python_前5名:使用AI指导足球,Python登录指南等
  9. [附源码]计算机毕业设计Node.js企源饮料销售网站(程序+LW)
  10. 思普linux安装教程,思普操作系统下载地址|思普国产操作系统好用吗_好特教程...