第四章 复合数据类型

基础数据类型是Go语言世界的原子

复合数据类型包括四种:slice、map、 struct、array

数组和结构体是聚合类型,它们的值由许多元素或成员构成,数组和结构体都是固定内存大小的数据结构,,相比之下,slice和map则是动态的数据结构,它们将根据动态增长

4.5 JSON

JavaScript对象表示法(JSON)是一种用于发送和接收结构化信息的标准协议。类似的协议还有XML、ASN.1和Google的Protocol Buffer等,但JASON应用的最广泛

Go语言中对JSON的支持是encoding/json包

JSON是对JavaScript中各种类型的值-字符串、数字、布尔值和对象—Unicode本文编码,它可以用有效可读的方式表示基础数据类型和聚合数据类型

基本的JSON类型有数字(十进制或科学记数法)、布尔值、字符串,其中字符串是以双引号包含的Unicode字符序列,支持和Go语言类似的反斜杠转义特性,不过JSON使用的是\Uhhhh转义数字来表示一个UTF-16编码,而不是Go语言的rune类型

这些基础类型可以通过JSON的数组和对象类型进行递归组合。

一个JSON数组是一个有序的值序列,写在一个方括号中并以逗号分隔;一个JSON数组可以用于编码Go语言的数组和slice

一个JSON对象是一个字符串到值的映射,写成以系列的name:value对形式,用花括号包含并以逗号分隔;JSON的对象类型可以用于编码Go语言的map类型(key类型是字符串)和结构体,例如:

boolean     true
number      -273.15
string      "she said \"Hello, BF\""
array       ["gold","silver","bronze"]
objetct     {"year":1980,"event":"archery","medals":["gold","sliver","bronze"]}

思考一个程序:该程序负责收集各种电影评论并提供反馈功能,它的Movie数据类型和一个典型的表示电影的值列表如下所示:

type Movie struct {Title stringYear int `json:"released"`Color bool `json:"color.omitempty"`Actors []string
}
var movies = []Movie{{Title: "Casablanca",Year: 1942,Color: false,Actors: []string{"Humphrey Bogart","Ingrid Bergman"}},{Title: "Cool and Luck",Year: 1967,Color: true,Actors: []string{"Paul Newman"}},{Title: "Bullitt",Year: 1968,Color: true,Actors: []string{"Steve McQueen","Jacqueline Bisset"}},
}

类似这样的数据结构特别适合JSON格式,并且在两种之间相互转换也很容易

将一个Go语言中类似movies的结构体slice转为JSON的过程叫编组,编组通过调用json.Marshal 函数完成:

data,err := json.Marshal(movies)
if err != nil {log.Fatalf("JSON marchaling failed: %s",err)
}
fmt.Printf

Marshling函数返还一个编码后的字节slice,包含很长的字符串,并且没有空白缩进;我们将它折行以便于显示

[{"Title":"Casablanca","released":1942,"color.omitempty":false,"Actors":["Humphrey Bogart","Ingrid Bergman"]},{"Title":"Cool and Luck","released":1967,"color.omitempty":true,"Actors":["Paul Newman"]},{"Title":"Bullitt","released":1968,"color.omitempty":true,"Actors":["Steve McQueen","Jacqueline Bisset"]}]

这种紧凑的格式虽然包含了全部信息,但是很难阅读,另一个函数则能产生整齐的缩进,该函数有两个额外的参数用于表示每一行输出的前缀和每一个层级的缩进

data1,err1 := json.MarshalIndent(movies,"","   ")
if err1 != nil {log.Fatalf("JSON marchaling failed: %s",err)
}
fmt.Printf("%s\n",data1)
[{"Title": "Casablanca","released": 1942,"color.omitempty": false,"Actors": ["Humphrey Bogart","Ingrid Bergman"]},{"Title": "Cool and Luck","released": 1967,"color.omitempty": true,"Actors": ["Paul Newman"]},{"Title": "Bullitt","released": 1968,"color.omitempty": true,"Actors": ["Steve McQueen","Jacqueline Bisset"]}
]

在编码时,默认使用Go语言结构体成员的名字作为JSON对象(通过reflect反射技术),只有导出的结构体成员才会被编码

结构体tag:一个结构体成员Tag是在编译阶段关联到该成员的元信息字符串。结构体成员的Tag可以是任意字符串面值,但是通常是以系列空格分隔的key:“value”键值对序列,因为值中含有双引号字符,因此Tag一般用原生字符串面值的形式书写

Year int `json:"released"`
Color bool `json:"color.omitempty"`

json开头的键名对应的值用于控制encoding/json包的编码和解码行为,并且encoding/…下面其他的包也遵循这个约定。成员Tag中json对应值的第一部分用于指定JSON对象的名字,比如将Go语言中的TotalCount 成员对应到JSON中的total_count对象。Color成员的Tag还带了一个额外的omitempty选项,表示当Go语言结构体为空或零值时不生成JSON对象。果然,Casablanca是一个黑白电影,并没有输出Color成员

编码的逆操作时解码,对应将JSON数据解码为Go语言的数据结构,Go语言中一般叫unmarshaling,通过json.Unmashal函数完成

如下将JSON格式的电影数据解码为一个结构体slice,结构体中只有Title成员。通过定义合适的Go语言数据结构,我们可以选择性的解码

JSON中感兴趣的成员,这样其他JSON成员会被忽略

var titles []struct{Title string}
if err2 := json.Unmarshal(data,&titles);err2 != nil{log.Fatalf("JSON unshaling failed: %s ",err2)
}
fmt.Println(titles)//[{Casablanca} {Cool and Luck} {Bullitt}]

许多Web服务都提供JSON接口,通过HTTP接口发送JSON格式请求并返回JSON格式的信息。我们通过GitHub的issue查询服务来演示此用法

我们先来定义合适的类型和常量

const IssueURL = "https://api.github.com/search/issues"
type IssuesSearchResult struct {TotalCount int `json:"total_count"`Items []*Issue
}
type Issue struct {Number intHTMLURL string `json:"html_url"`Title stringState stringUser  *UserCreateAt time.Time `json:"create_at"`Body string
}
type User struct {Login stringHTMLURL string `json:"html_url"`
}

和前面一样,即使对应的JSON对象名是小写字母,每个结构体的成员名也是声明为大写字母开头的。因为有些JSON成员名字和Go结构体成员名字并不相同。同样,在解码的时候也需要做同样的处理,Github服务返回的信息比我们定义的要多很多

SearchIssues函数发出一个HTTP请求,然后解码返回的JSON格式的结果,因为用户提供的查询条件可能包含类似?和&之类的特殊字符,为了避免对URL造成冲突,我们用url.QueryEscape来对查询中的特殊字符进行转义操作

func SearchIssues(terms []string) (*IssuesSearchResult, error) {q := url.QueryEscape(strings.Join(terms, " "))resp, err := http.Get(IssueURL + "?q=" + q)if err != nil {return nil, err}if resp.StatusCode != http.StatusOK {resp.Body.Close()return nil, fmt.Errorf("search query failed:%s", resp.Status)}var result IssuesSearchResultif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {resp.Body.Close()return nil, err}resp.Body.Close()return &result, nil
}

在之前,我们使用了json.Unmarshal函数来将JSON格式的字符串解码为字节slice,但是在这个例子中,我们使用了基于流式解码器json.Encoder编码对象

我们调用Decode方法来填充变量,这里有多种方法可以格式化结构。下面是最简单的一种,以一个固定宽度打印每一个issue,但是在下一节我们将看到如何利用模板来输出复杂的格式

func main() {result,err := github.SearchIssues(os.Args[1:])if err != nil{log.Fatal(err)}fmt.Printf("%d issues\n",result.TotalCount)for _,item :=range result.Items{fmt.Printf("#%-5d %9.9s %.55s\n",item.Number,item.User.Login,item.Title)}
}

通过命令行参数指定检索条件,即可得到结果,Github的Web服务接口Https://developer.github.com/v3/包含了更多特性

Go语言圣经 - 第4章 复合数据类型 - 4.5 JSON相关推荐

  1. Go语言圣经 - 第3章 基础数据类型

    第3章 基础数据类型 Go语言将数据类型分为了四类:基础类型.符合类型.引用类型和接口类型.基础类型:数字.字符串和布尔型:复合数据类型:数组和结构体:引用类型:指针.切片.字典.函数.通道,虽然数据 ...

  2. 《Go语言圣经》学习笔记 第四章 复合数据类型

    <Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...

  3. 《Go语言圣经》第一章 - 读书笔记

    <Go语言圣经>第一章 - 读书笔记 第一章 Go语言入门 01 Hello World 02 命令行参数 练习 练习1.1 练习1.2: 练习1.3: 03 查找重复的行 例子运行 du ...

  4. c语言求两者之间最小数,C语言课件第2章基本数据类型.ppt

    C语言课件第2章基本数据类型 第 2 章 基本数据类型 1.标识符 例2.1 常量和变量的使用. #include "stdio.h" #define WIDTH 80 //定义符 ...

  5. Python语言程序设计第七章 - 组合数据类型 - 6.1

    目录 Python语言程序设计第七章 - 组合数据类型 集合运算 集合的关系 集合综合练习 元组元素抓7 元组解包 升序降序 截取部分元素 判断元素书否在列表中存在 头尾对调 翻转列表 指定元素对调 ...

  6. 字符串是单一字符的无序组合吗_计算机二级教程 Python语言程序设计 第6章组合数据类型...

    第6章组合数据类型 第六章学习知识导图 考点主要是: 1) 组合数据类型的基本概念 2) 列表类型:定义.索引.切片 3) 列表类型的操作:列表的操作函数.列表的操作方法 4) 字典类型:定义.索引 ...

  7. Go语言圣经 - 第8章 Goroutines 和 Channels - 8.8 示例:并发的目录遍历

    第8章 Goroutines 和 Channels Go语言中的并发程序可以用两种手段来实现:goroutine 和 channel,其支持顺序通信进程,或被简称为CSP,CSP是一种并发编程模型,在 ...

  8. Go语言圣经 - 第1章 入门 - 1.3 1.4 查找重复的行 GIF

    第1章 入门 1.3 查找重复的行 在1.2节,我们简单的了解了一些Go语言的基本语法,接下来我们再来看一个例子进一步学习 对文件做拷贝.打印.搜索和排序.统计或类似事情的程序都有一个差不多的程序结构 ...

  9. 01 C语言程序设计--01 C语言基础--第3章 基本数据类型01

    01.1.3.1序言 00:02:17 01.1.3.2 C语言中的基本元素和常量的概念 00:08:54 01.1.3.3示例--常量 00:12:08 01.1.3.4变量的概念和命名规则 00: ...

最新文章

  1. stm32 cubemx hal 工程中 微秒延迟 delay_us
  2. 无需额外数据、Tricks、架构调整,CMU开源首个将ResNet50精度提升至80%+新方法
  3. pip19离线_更新pip为20后不显示下载链接无法离线下载回退pip版本
  4. Java 中常用缓存Cache机制的实现
  5. 【译】Jumping into Solidity — The ERC721 Standard (Part 4)
  6. ⚡如何在2分钟内将GraphQL服务器添加到RESTful Express.js API
  7. ArcSDE的版本管理机制
  8. java.util.ArrayList
  9. ThinkPHP redirect 传参
  10. 爬虫实战(一)之爬取房天下新房数据
  11. 毕设题目:Matlab优化覆盖
  12. coap协议详解 服务器,COAP协议解析和简单打包实现
  13. 【Python基础】from pygame.base import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] Mod
  14. 练习如下命令的使用: set mset get mget keys type exists ttl expire move 、select del flushdb flusha
  15. iOS获取本地音乐文件
  16. JavaEE - 数组
  17. UI设计师都在用的4款UI设计软件
  18. Mybatis源码-cursor(游标)
  19. 描绘新十年智慧生活蓝图,AWE2021圆满闭幕
  20. C++之类和对象基础认知

热门文章

  1. 马尔科夫与隐马尔可夫总结
  2. EXTJS 中grid 动态增加列的方法
  3. CMake是什么?具体有什么作用?
  4. 看了那么多文章,终于弄懂了脏读、不可重复度、幻读
  5. 聊聊FlutterEngage大会中的特性落地
  6. Ubuntu上装KVM:安装、初次使用
  7. JavaScript:简易ATM机案例
  8. 永磁材料知识—钕铁硼
  9. 多项式求逆与多项式除法/取模
  10. IT类科技公司门户网站建设方案