| 作者 |
| 杰伊·麦克格瑞恩 艾伦A. A.多诺万 布莱恩W.柯尼汉 |
| 丛书名 |
| O’Reilly精品图书系列 |
| 出版社 |
| 机械工业出版社 |
| ISBN |
| 9782009221618 |
| 简要 |
| 简介 |
| 内容简介书籍计算机书籍 ---------------------------Head First Go语言程序设计--------------------------- Go是为高性能网络和多处理而设计的, 但与python和javascript一样,该语言易于阅读和使用。通过这本实用的实践指南,读者将学习如何使用演示实际语言的清晰示例来编写Go代码。最重要的是,读者将会了解到用人单位希望入门级Go开发人员所知晓的惯例和技术。主要内容包括语法基础、条件和循环、函数、包、数组、映射、结构、封装和嵌入、接口、故障恢复、共享、自动化测试、Web应用程序等。 ---------------------------Go程序设计语言--------------------------- 本书由《C程序设计语言》的作者Kernighan和谷歌公司Go团队主管Alan Donovan联袂撰写,是学习Go语言程序设计的权威指南。本书共13章,主要内容包括:Go的基础知识、基本结构、基本数据类型、复合数据类型、函数、方法、接口、goroutine、通道、共享变量的并发性、包、go工具、测试、反射等。 本书适合作为计算机相关专业的教材,也可供Go语言爱好者阅读。 |
| 目录 |
---------------------------Head First Go语言程序设计--------------------------- (概要) 如何使用这本书:前言 xxvii 1 让我们开始吧:语法基础 1 2 接下来运行哪些代码:条件和循环 31 3 调用:函数 79 4 代码集:包 113 5 列表:数组 149 6 追加的问题:切片 175 7 标签数据:映射 205 8 构建存储:struct 231 9 我喜欢的类型:定义类型 265 10 保密:封装和嵌入 289 11 你能做什么:接口 321 12 重新站起来:从失败中恢复 349 13 分享工作:goroutine和 channel 379 14 代码的质量保证:自动化测试 401 15 响应请求:Web应用程序 425 16 要遵循的模式:HTML模板 445 A 理解os.OpenFile:打开文件 481 B 有六件事我们没有涉及:剩下的内容 495 (真正的) 如何使用这本书 前言 你的大脑如何看待Go。在这里,你试图学习一些东西,而你的大脑 在帮你的忙,确保学习不会停滞不前。你的大脑在想:“最好给更重要的 事情留点儿空间,比如避开哪些野生动物,裸体滑雪是否是个坏主意。” 那么,你如何欺骗你的大脑,让它认为你的生活依赖于如何用Go编程呢 这本书是给谁看的 xxviii 我们知道你在想什么 xxix 我们知道你的大脑在想什么 xxix 元认知:思考“何为思考” xxxi 我们是这样做的 xxxii 说明 xxxiv 致谢 xxxv 1让我们开始吧 语法基础 准备好给你的软件充电了吗你想要一种编译速度快的简单编程语言吗它跑 得快吗它可以很容易地将你的工作分发给用户吗那就准备好学习Go吧! Go是一种注重简单性和速度的编程语言。它比其他语言都简单,所以学起来更快。它 可以让你利用当今多核计算机处理器的能力,使你的程序运行得更快。本章将向你展 示所有Go的功能,这些功能将使你作为开发人员的生活更轻松,并使你的用户更快乐。 准备好,出发 2 Go Playground 3 这一切意味着什么 4 如果出了问题怎么办 5 调用函数 7 Println函数 7 使用其他包中的函数 8 函数返回值 9 Go程序模板 11 字符串 11 符文 12 布尔值 12 数字 13 数学运算与比较 13 类型 14 声明变量 16 零值 17 短变量声明 19 命名规则 21 转换 22 在你的计算机上安装Go 25 编译Go代码 26 Go工具 27 使用“go run”快速尝试代码 27 你的Go 工具箱 28 package main import fmt func main() { } fmt.Println( ) Hello, Go! Hello, Go! 1+ 2 true 3 4 viii '?' 1174 输出 2 接下来运行哪些代码 条件和循环 每个程序都有仅在特定情况下适用的部分。“如果出现错误,应该运行 这段代码。否则,应该运行其他代码。”几乎每个程序都包含只有在特定条件为真时才 应该运行的代码。因此,几乎每种编程语言都提供条件语句,让你决定是否运行某段代 码。Go也不例外。 你可能还需要重复运行代码中的某些部分。与大多数语言一样,Go提供了循环, 可以多次运行某部分代码。在本章中,我们将学习使用条件句和循环! 调用方法 32 评分 34 函数或方法的多个返回值 36 选项1:使用空白标识符忽略错误返回值 37 选项2:处理错误 38 条件 39 有条件地记录致命错误 42 避免遮盖名字 44 将字符串转换为数字 46 块 49 块和变量的作用域 50 我们已经完成了评分程序 52 短变量声明中只有一个变量必须是新的 54 让我们创建一个游戏 55 包名与导入路径 56 生成随机数 57 从键盘获取整数 59 将猜测与目标进行比较 60 循环 61 初始化和标志(post)语句是可选的 63 在我们的猜谜游戏中使用循环 66 中断我们的猜测循环 69 显示目标 70 恭喜你,游戏结束了 72 你的Go工具箱 74 条件语句块 结束 条件语句块 开始 条件语句块主体 “if”关键字 条件 if 1fmt.Println(It's true!) } 3 调用 函数 你错过了机会。你一直像专业人士一样调用函数。但你唯一能调用的函数是 Go为你定义的函数。现在,轮到你了。我们将向你展示如何创建你自己的函数。 我们将学习如何声明带参数和不带参数的函数。我们将声明返回单个值的函数, 并且我们将学习如何返回多个值,以便我们可以指示何时发生了错误。我们还将 学习指针,它允许我们进行更有效的内存函数的调用。 一些重复的代码 80 使用Printf和Sprintf格式化输出 81 格式化动词 82 格式化值宽度 83 格式化小数宽度 84 在油漆计算器中使用Printf 85 声明函数 86 声明函数参数 87 在油漆计算器中使用函数 88 函数和变量的作用域 90 函数返回值 91 在油漆计算器中使用返回值 93 paintNeeded函数需要错误处理 95 错误值 96 声明多个返回值 97 在paintNeeded函数中使用多个返回值 98 始终处理错误 99 函数形参接收实参的副本 102 指针 103 指针类型 104 获取或更改指针的值 105 函数指针 107 使用指针修复我们的“double”函数 108 你的Go工具箱 110 4 代码集 包 是时候整理一下了。到目前为止,我们一直将所有代码放在一个文件中。 随着我们的程序变得越来越大、越来越复杂,这很快就会变得一团糟。 在本章中,我们将向你展示如何创建自己的包,以帮助将相关代码集中放在 一个地方。但是包不仅仅对组织结构有益,它还是在程序之间共享代码的一种简单方法,同时也是与其他开发人员共享代码的一种简单方法。 不同的程序,相同的函数 114 使用包在程序之间共享代码 116 Go工作区保存包代码 117 创建一个新包 118 将包导入程序 119 包使用相同的文件布局 120 包命名规范 123 包限定符 123 将共享代码移动到包中 124 常量 126 嵌套的包和导入路径 128 使用“go install”安装程序可执行文件 130 使用GOPATH环境变量更改工作区 131 设置GOPATH 132 发布包 133 使用“go get”下载和安装包 137 使用“go doc”阅读包文档 139 使用doc注释记录包 141 在Web浏览器中查看文档 143 使用“godoc”提供HTML文档 144 “godoc”服务器包含你的包 145 你的Go工具箱 146 go bin hi pkg src greeting greeting.go hi main.go 5 列表 数组 很多程序都处理列表。地址列表、电话号码列表、产品列表。Go有两种内置 的存储列表的方法。本章将介绍第一种:数组。你将了解如何创建数组,如何用数 据填充数组,以及如何重新获取这些数据。然后你将学习如何处理数组中的所有元 素,首先是使用for循环的困难些的方法,然后是使用for...range循环的简单 些的方法。 数组保存值的集合 150 数组中的零值 152 数组字面量 153 “fmt”包中的函数知道如何处理数组 154 在循环里访问数组元素 155 使用“len”函数检查数组长度 156 使用“for ... range”安全遍历数组 157 在“for ... range”循环中使用空白标识符 158 得到数组中数字之和 159 得到数组中数字的平均值 161 读取文本文件 163 将文本文件读入数组 166 更新我们的“average”程序来读取文本文件 168 我们的程序只能处理三个值 170 你的Go工具箱 172 数组中将要存储的元素类型 数组中将要存储的元素个数 var myArray [4]string 索引0 索引1 索引2 索引3 6 追加的问题 切片 我们已经知道了无法将更多的元素增加到一个数组中。对于程序的确是个问题。因为我们无法提前知道文件中包含多少个块。而这就是Go中的切片 (slice)的用武之地。切片是一个可以通过增长来保存额外数据的集合类型,正好能够满足程序的需要!我们将看到切片是如何让用户以简洁的方式在程序中提供 数据的,以及如何帮助你写出更加方便调用的函数。 切片 176 切片字面量 177 切片运算符 180 底层数组 182 修改底层数组,修改切片 183 使用“append”函数在切片上添加数据 184 切片和零值 186 使用切片和“append”读取额外的文件行 187 尝试我们改进后的程序 189 出错时返回nil值切片 190 命令行参数 191 从os.Args切片获取命令行参数 192 切片运算符可用于其他切片 193 更新程序以使用命令行参数 194 可变长参数函数 195 使用可变长参数函数 197 使用可变长参数函数计算平均值 198 向可变长参数函数传递一个切片 199 切片拯救了我们 201 你的Go工具箱 202 切片 底层数组 数组1 切片1 {a, b, c, d, e} 7 标签数据 映射 堆积物品是个好方法,直到你需要再次找到它。你已经看到了如何使用 切片和数组来创建一列数据。但是当你需要使用一个特定的值时会怎样为了找 到它,你需要从数组或者切片的开头开始,查看每一个元素。 如果有一种集合,其中的每个值都有个标签在上面,那么你就可以快速找到你需 要的值!在这一章,我们来看映射,它就是做这个的。 计票 206 从文件中读取名字 207 使用困难的切片方法对名字计数 209 映射 212 映射字面量 214 映射中的零值 215 映射变量的零值是nil 215 如何区分已经赋值的值和零值 216 使用“delete”函数删除键/值对 218 使用映射来更新计票程序 219 对映射进行for ... range循环 221 for ... range循环以随机顺序处理映射 223 使用for ... range循环来更新计票程序 224 计票程序完成 225 你的Go工具箱 227 Carlos Diaz Amber Graham Brian Martin Mikey Moose 键可以使你快速 找到数据! 8 构建存储 struct 有时你需要保存超过一种类型的数据。我们学习了切片,它能够保存 一组数据。然后学习了映射,它能保存一组键和一组值。这两种数据结构都只 能保存一种类型。有时,你需要一组不同类型的数据,例如邮件地址,混合了 街道名(字符串类型)和邮政编码(整型);又如学生记录,混合保存学生名 字和成绩(浮点数)。你无法用切片或者映射来保存。但是你可以使用其他的名为struct的类型来保存。本章会介绍struct的所有信息! 切片和映射保存一种类型的值 232 struct是由多种类型的值构建的 233 使用点运算符访问struct字段 234 在struct中保存订阅者的数据 235 定义类型和struct 236 为杂志订阅者定义一个类型 238 与函数一起使用已定义类型 239 使用函数修改struct 242 通过指针访问struct的字段 244 使用指针传递大型struct 246 将struct类型移动到另一个包 248 定义类型的名称首字母必须大写才能导出该类型 249 struct字段的名称首字母必须大写才能导出该字段 250 struct字面量 251 创建一个Employee struct类型 253 创建一个Address struct类型 254 将struct作为字段增加到另一个类型中 255 在另一个struct中设置struct 255 匿名struct字段 258 嵌入struct 259 我们定义的类型完成了 260 你的Go工具箱 261 9 我喜欢的类型 定义类型 定义类型还有更多内容需要学习。在之前的章节,我们展示了如何使用 strcut基础类型来定义类型。没有展示如何使用任意类型作为基础类型。 但是你记得方法——与特定值类型关联的特殊的函数吗我们在整本书中都在调 用多种值的方法,但是没有展示如何定义自己的方法。在本章中,我们打算介 绍。让我们开始吧! 现实生活中的类型错误 266 具有底层基础类型的定义类型 267 定义类型和运算符 269 使用函数进行类型转换 271 使用方法修复函数名冲突 274 定义方法 275 接收器参数(几乎)就是另一个参数 276 方法(几乎)就像一个函数 277 指针类型的接收器参数 279 使用方法将Liters和Milliliters转换为Gallons 283 使用方法将Gallons转换为Liters和Milliliters 284 你的Go工具箱 285 Steve认为他 买了多少。 Steve实际上 买了多少! 10 加仑 10 升 10 保密 封装和嵌入 错误总会发生。有时,你的程序会接收到无效的数据,从用户输入、从文件读取或以其他方式。在本章,你会学到封装:一个保护struct字段免受无效数据的 方法。这样,你的数据字段能够安全地使用。 我们也会在你的类型内部嵌入其他的类型。如果你的struct类型需要已经存在 于其他类型的方法,你不需要拷贝粘贴方法代码。你可以将其他类型嵌入你的 struct类型中,然后像使用你自己的类型的定义方法一样使用嵌入类型的方法! 创建一个日期struct类型 290 人们将Date struct的字段设置为无效值 291 setter方法 292 setter方法需要指针接收器 293 添加其余的setter方法 294 在setter方法中添加校验 296 字段仍可以设置为无效值 298 将Date类型移到另外的包中 299 将Date字段设为未导出状态 301 通过导出的方法访问未导出的字段 302 getter方法 304 封装 305 在Event类型中嵌入Date类型 308 未导出的字段不会被提升 309 导出的方法像字段一样被提升 310 封装Event的Title字段 312 提升的方法与外部类型的方法共存 313 我们的calendar包完成了 314 你的Go工具箱 316 当人们实际使用setter方法时,它们提供的校验非常 棒。但是我们已经让人们直接设置struct字段,他们 仍然在输入无效数据! 11 你能做什么 接口 有时你并不关心一个值的特定类型。你不需要关心它是什么。你只需要 知道它能做特定的事情。你能够在其上调用特定的接口。不需要关心是pen还是 pencil,你仅仅需要一个Draw方法。不需要关心是Car还是Boat,你只需要一个 Steer方法。 那就是Go接口的目标。它允许你定义能够保存任何类型的变量和函数参数,前提 是它定义了特定的方法。 具有相同方法的两种不同类型 322 只能接受一种类型的方法参数 323 接口 325 定义满足接口的类型 326 具体类型和接口类型 327 分配满足接口的任何类型 328 你只能调用接口中定义的方法 329 使用接口修复playList函数 331 类型断言 334 类型断言失败 336 当类型断言失败时避免异常 337 使用类型断言测试TapePlayer和TapeRecorder 338 “error”接口 340 Stringer接口 342 空接口 344 你的Go工具箱 347 播放器 录音机 12 重新站起来 从失败中恢复 每个程序都会遇到错误,你应该为它们做好计划。有时候,处理错误 可以像报告错误并退出程序一样简单。但是其他错误可能需要额外的操作。你可 能需要关闭打开的文件或网络连接,或者以其他方式清理,这样你的程序就不会 留下混乱。在本章中,我们将向你展示如何延迟清理操作,以便在出现错误时也 能执行这些操作。我们还将向你展示如何在适当的(罕见的)情况下使程序出现panic,以及如何在事后恢复。 从文件中读取数字,重新访问 350 任何错误都将阻止关闭文件 352 延迟函数调用 353 使用延迟函数调用从错误中恢复 354 使用延迟函数调用确保文件关闭 355 列出中的文件 358 列出子中的文件(会更棘手) 359 递归函数调用 360 递归地列出内容 362 递归函数中的错误处理 364 发起一个panic 365 堆栈跟踪 366 延迟调用在崩溃前完成 366 通过scanDirectory 使用“panic” 367 何时产生panic 368 “recover”函数 370 panic值从recover中返回 371 从scanDirectory中的panic恢复 373 恢复panic 374 你的Go工具箱 376 不能转换成 float64类型! 20.25 hello 10.5 bad-data.txt 13 分享工作 goroutine和channel 一次只做一件事并不总是完成任务最快的方法。一些大问题可以分解 成小任务。goroutine可以让程序同时处理几个不同的任务。goroutine可以使用 channel来协调它们的工作,channel允许goroutine互相发送数据并同步,这样一 个goroutine就不会领先于另一个goroutine。goroutine让你充分利用具有多处理 器的计算机,让程序运行得尽可能快! 检索网页 380 多任务 382 使用goroutine的并发性 383 使用goroutine 384 在responseSize函数中使用goroutine 386 我们不能直接控制goroutine何时运行 388 go语句不能使用返回值 389 使用channel发送和接收值 391 同步goroutine与channel 392 观察goroutine同步 393 使用channel修复我们的网页大小程序 396 更新我们的channel以携带一个struct 398 你的Go工具箱 399 接收端goroutine等待另一个 goroutine的发送值。 14 代码的质量保证 自动化测试 你确定你的软件工作良好吗真的确定吗 在将新版本发给用户之前, 你可能已经尝试了新特性,以确保它们都能正常工作。但你有没有尝试过旧的 特性,以确保你没有破坏它们中的任何一个所有的旧特性如果这个问题让你担 心,那么你的程序需要自动化测试。自动化测试确保程序的组件能够正确工作, 即使在你更改代码之后也是如此。Go的testing包和go test工具使用你已经学 习的技能,使编写自动化测试变得更加容易! 自动化测试比别人先发现bug 402 一个应该有自动化测试的函数 403 我们引入了一个bug 405 编写测试 406 使用“go test”命令运行测试 407 测试实际的返回值 408 使用“Errorf”方法获得更详细的测试失败消息 410 测试“helper”函数 411 让测试通过 412 测试驱动开发 413 另一个需要修复的bug 414 运行特定的测试集 417 表驱动测试 418 使用测试修复panic代码 420 你的Go工具箱 422 通过。 对于 []slice{apple, orange, pear}, JoinWithCommas 应返回 apple, orange, and pear。 失败! 对于 []slice{apple, orange}, JoinWithCommas 应返回 apple and orange。 15 响应请求 Web应用程序 这是21世纪。用户需要Web应用程序。Go在这里已经覆盖了!Go标准库包 含一些包,可以帮助你托管自己的Web应用程序,并使它们可以从任何Web浏览器 访问。因此,我们将在本书的最后两章向你展示如何构建Web应用程序。 Web应用程序需要做的第一件事是当浏览器向它发送请求时能够做出响应。在本章 中,我们将学习如何使用net/http包来实现这一点。 用Go编写Web应用程序 426 浏览器、请求、服务器和响应 427 一个简单的Web应用程序 428 你的计算机在自言自语 429 讲解一个简单的Web应用程序 430 资源路径 432 对不同的资源路径做出不同的响应 433 一级函数 435 将函数传递给其他函数 436 函数作为类型 436 接下来是什么 440 你的Go工具箱 441 example.com: GET /hello GET /hello Hello, web! example.com 你的Go程序 Hello, web! 16 要遵循的模式 HTML模板 你的Web应用程序需要用HTML而不是纯文本进行响应。纯文本可以 用于电子邮件和社交媒体帖子。但是你的页面需要格式化。它们需要标题和段落。 它们需要用户可以向你的应用程序提交数据的表单。要做到这一点,你需要HTML代码。 最后,你需要将数据插入HTML代码中。这就是Go提供html/template包的原因, 这是一种在应用程序的HTML响应中包含数据的强大方法。模板是构建更大、更好的Web应用程序的关键,在这最后的一章里,我们将向你展示如何使用它们! 留言簿应用程序 446 处理请求和检查错误的函数 447 设置一个项目并尝试应用程序 448 用HTML创建签名列表 449 使我们的应用程序以HTML响应 450 “text/template”包 451 使用带有模板的Execute方法的io.Writer接口 452 满足io.Writer的ResponseWriter和os.Stdout 453 使用action将数据插入模板 454 使用“if”action使模板的某些部分可选 455 使用“range”action来重复模板的某部分 456 使用action将struct字段插入模板 457 从文件中读入签名切片 458 保存签名和签名数的struct 460 更新模板以包含签名 461 允许用户使用HTML表单添加数据 464 表单提交请求 466 用于表单提交的Path和HTTP方法 467 从请求中获取表单字段的值 468 保存表单数据 470 HTTP重定向 472 我们完整的应用程序代码 474 你的Go工具箱 477 响应主留言簿页面的请求。 使用HTML格式化响应。 使用签名填充HTML页面。 设置用于添加新签名的 表单。 保存提交的签名。 A 理解os.OpenFile 打开文件 有些程序需要将数据写入文件,而不仅仅是读取数据。在整本书中, 当我们想要处理文件时,必须在文本编辑器中创建它们,以便程序读取。但是有 些程序生成数据,当生成数据时,程序需要能够将数据写入文件。 在本书的前面,我们使用os.OpenFile函数打开一个文件,以便写入。但我们当 时没有足够的空间来充分探索它是如何工作的。在本附录中,我们将向你展示有 效使用os.OpenFile所需的所有知识! 理解os.OpenFile 482 将标志常量传递到os.OpenFile 483 二进制表示法 485 位运算符 485 按位与运算符 486 按位或运算符 487 对“os”包常量使用按位或运算 488 使用按位或运算修复os.OpenFile选项 489 Unix样式的文件权限 490 使用os.FileMode类型表示权限 491 八进制表示法 492 将八进制值转换为FileMode值 493 解释对os.OpenFile的调用 494 这次将把新文本 追加到文件中。 Aardvarks are... amazing! aardvark.txt B 有六件事我们没有涉及 剩下的内容 我们已经讲了很多内容,你几乎看完了这本书。我们会想念你的,但在 让你离开之前,如果不多做一点准备就把你送到这个世界上去,我们会觉得不太 合适。我们为本附录保存了六个重要的主题。 #1 “if”的初始化语句 496 #2 switch语句 498 #3 更多基本类型 499 #4 更多关于符文的信息 499 #5 有缓冲的channel 503 #6 进一步阅读 506 初始化语句 条件 if count := 5; count > 4 { fmt.Println(count is, count) } 0: A 1: B 2: C 3: D 4: E 0: Б 2: Г 4: Д 6: Ж 8: И d c b a 额外发送的值将添加到缓冲 区中,直到缓冲区满为止。 所有字符都是可打印的。 当缓冲区已满时发送一个值会导致发送goroutine的阻塞。 ---------------------------Go程序设计语言--------------------------- 出版者的话 译者序 前言 第1章 入门 1 1.1 hello,world 1 1.2 命令行参数 3 1.3 找出重复行 6 1.4 GIF动画 10 1.5 获取一个URL 12 1.6 并发获取多个URL 13 1.7 一个Web服务器 14 1.8 其他内容 17 第2章 程序结构 20 2.1 名称 20 2.2 声明 21 2.3 变量 22 2.3.1 短变量声明 22 2.3.2 指针 23 2.3.3 new函数 25 2.3.4 变量的生命周期 26 2.4 赋值 27 2.4.1 多重赋值 27 2.4.2 可赋值性 28 2.5 类型声明 29 2.6 包和文件 30 2.6.1 导入 31 2.6.2 包初始化 33 2.7 作用域 34 第3章 基本数据 38 3.1 整数 38 3.2 浮点数 42 3.3 复数 45 3.4 布尔值 47 3.5 字符串 47 3.5.1 字符串字面量 49 3.5.2 Unicode 49 3.5.3 UTF-8 50 3.5.4 字符串和字节slice 53 3.5.5 字符串和数字的相互转换 56 3.6 常量 56 3.6.1 常量生成器iota 57 3.6.2 无类型常量 59 第4章 复合数据类型 61 4.1 数组 61 4.2 slice 63 4.2.1 append函数 66 4.2.2 slice就地修改 69 4.3 map 71 4.4 结构体 76 4.4.1 结构体字面量 78 4.4.2 结构体比较 80 4.4.3 结构体嵌套和匿名成员 80 4.5 JSON 82 4.6 文本和HTML模板 87 第5章 函数 92 5.1 函数声明 92 5.2 递归 93 5.3 多返回值 96 5.4 错误 98 5.4.1 错误处理策略 99 5.4.2 文件结束标识 101 5.5 函数变量 102 5.6 匿名函数 104 5.7 变长函数 110 5.8 延迟函数调用 111 5.9 宕机 115 5.10 恢复 118 第6章 方法 120 6.1 方法声明 120 6.2 指针接收者的方法 122 6.3 通过结构体内嵌组成类型 124 6.4 方法变量与表达式 127 6.5 示例:位向量 128 6.6 封装 130 第7章 接口 133 7.1 接口即约定 133 7.2 接口类型 135 7.3 实现接口 136 7.4 使用flag.Value来解析参数 139 7.5 接口值 141 7.6 使用sort.Interface来排序 144 7.7 http.Handler接口 148 7.8 error接口 152 7.9 示例:表达式求值器 154 7.10 类型断言 160 7.11 使用类型断言来识别错误 161 7.12 通过接口类型断言来查询特性 162 7.13 类型分支 164 7.14 示例:基于标记的XML解析 166 7.15 一些建议 168 第8章 goroutine和通道 170 8.1 goroutine 170 8.2 示例:并发时钟服务器 171 8.3 示例:并发回声服务器 174 8.4 通道 176 8.4.1 无缓冲通道 177 8.4.2 管道 178 8.4.3 单向通道类型 180 8.4.4 缓冲通道 181 8.5 并行循环 183 8.6 示例:并发的Web爬虫 187 8.7 使用select多路复用 190 8.8 示例:并发遍历 192 8.9 取消 195 8.10 示例:聊天服务器 198 第9章 使用共享变量实现并发 201 9.1 竞态 201 9.2 互斥锁:sync.Mutex 205 9.3 读写互斥锁:sync.RWMutex 208 9.4 内存同步 208 9.5 延迟初始化:sync.Once 210 9.6 竞态检测器 212 9.7 示例:并发非阻塞缓存 212 9.8 goroutine与线程 218 9.8.1 可增长的栈 219 9.8.2 goroutine调度 219 9.8.3 GOMAXPROCS 219 9.8.4 goroutine没有标识 220 第10章 包和go工具 221 10.1 引言 221 10.2 导入路径 221 10.3 包的声明 222 10.4 导入声明 223 10.5 空导入 223 10.6 包及其命名 225 10.7 go工具 226 10.7.1 工作空间的组织 227 10.7.2 包的下载 228 10.7.3 包的构建 229 10.7.4 包的文档化 231 10.7.5 内部包 232 10.7.6 包的查询 233 第11章 测试 235 11.1 go test工具 235 11.2 Test函数 236 11.2.1 随机测试 239 11.2.2 测试命令 240 11.2.3 白盒测试 242 11.2.4 外部测试包 245 11.2.5 编写有效测试 246 11.2.6 避免脆弱的测试 247 11.3 覆盖率 248 11.4 Benchmark函数 250 11.5 性能剖析 252 11.6 Example函数 254 第12章 反射 256 12.1 为什么使用反射 256 12.2 reflect.Type和reflect.Value 257 12.3 Display:一个递归的值显示器 259 12.4 示例:编码S表达式 263 12.5 使用reflect.Value来设置值 266 12.6 示例:解码S表达式 268 12.7 访问结构体字段标签 271 12.8 显示类型的方法 273 12.9 注意事项 274 第13章 低级编程 276 13.1 unsafe.Sizeof、Alignof 和Offsetof 276 13.2 unsafe.Pointer 278 13.3 示例:深度相等 280 13.4 使用cgo调用C代码 282 13.5 关于安全的注意事项 286 |