第 19 页
在 Go 语言中,所有的变量都以值得方式传递。因为指针变量的值是所指向的内存地址,在函数间传递指针变量,是在传递这个地址值,所以依旧被看作以值得方式在传递。
第 39 页
可以访问 http://golang.org/pkg/fmt/ 或者在终端输入 godoc fmt 来了解更多关于 fmt 包的细节。
第 40 页
使用分布式版本控制系统(Distributed Version Control System,DVCS)来分享代码,如 GitHub、Launchpad 还有 Bitbucket。Go 语言的工具链本身就支持从这些网站及类似网站获取源代码。
第 44 页
go vet 命令会帮开发人员检测代码的常见错误。
第 46 页
Go 语言有两种方法为开发者生成文档。可以在终端上直接使用 go doc 命令来打印文档。可以使用 godoc 程序来启动一个 Web 服务器,通过点击的方式来查看 Go 语言的包的文档。
go doc tar
godoc -http=:6060(这个命令通知 godoc 在端口 6060 启动 Web 服务器。如果浏览器已经打开,导航到 http://localhost:6060 可以看到一个页面,包含所有 Go 标准库和你的 GOPATH 下的 Go 源代码的文档)
第 53 页
在 Go 语言里,数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块。
因为其占用的内存是连续分配的,由于内存连续,CPU 能把正在使用的数据缓存更久的时间。而且内存连续很容易计算索引,可以快速迭代数组里的所有元素。数组的类型信息可以提供每次访问一个元素时需要在内存中移动的距离。既然数组的每个元素类型相同,又是连续分配,就可以以固定速度索引数组中的任意数据,速度非常快。
第 56 页
在 Go 语言里,数组是一个值。这意味着数组可以用在赋值操作中。变量名代表整个数组,因此,同样类型的数组可以赋值给另一个数组,复制之后,两个数组的值完全一样。
数组变量的类型包括数组长度和每个元素的类型。只有这两部分都相同的数组,才是类型相同的数组,才能互相赋值。
复制指针数组,只会复制指针的值,而不会复制指针所指向的值,复制之后,两个数组指向同一组字符串。
第 58 – 62 页
数组本身只有一个维度,不过可以组合多个数组创建多维数组。多维数组很容易管理具有父子关系的数据或者与坐标系相关联的数据。
只要类型一致,就可以将多维数组互相赋值,多维数组的类型包括每一维度的长度以及最终存储在元素中的数据的类型。
因为每个数组都是一个值,所以可以独立复制某个维度。
根据内存和性能来看,在函数间传递数组是一个开销很大的操作。在函数之间传递变量时,总是以值的方式传递的。如果这个变量是一个数组,意味着整个数组,不管有多长,都会完整复制,并传递给函数。
切片是一种数据结构,这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数append
来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的大小。因为切片的底层内存也是在连续块中分配的,所有切片还能获得索引、迭代以及为垃圾回收优化的好处。
切片有 3 个字段的数据结构,这些数据结构包含 Go 语言需要操作底层数组的元数据。这 3 个字段分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)。
使用内置的make
函数创建切片时,需要传入一个参数,指定切片的长度.如果只指定长度,那么切片的容量和长度相等。也可以分别制定长度和容量,创建的切片,底层数组的长度是指定的容量,但是初始化后并不能访问所有的数组元素。不允许创建容量小于长度的切片,容量小于长度的切片会在编译时报错。
如果在[]
运算符里指定了一个值,那么创建的就是数组而不是切片。只有不指定值的时候,才会创建切片。
第 64 页
切片之所以被称为切片,是因为创建一个新的切片就是把底层数组切出一部分。
第 66 页
函数append
总是会增加新切片的长度,而容量有可能会改变,也可能不会改变,这取决于被操作的切片的可用容量。
第 68 页
函数append
会智能地处理底层数组的容量增长。在切片的容量小于 1000 个元素时,总是会成倍地增加容量。一旦元素个数超过 1000,容量的增长因子会设为 1.25,也就是会每次增加 25% 的容量。随着语言的演化,这种增长算法可能会有所改变。
第 75 页
在函数间传递切片就是要在函数间以值的方式传递切片。由于切片的尺寸很小,在函数间复制和传递切片成本也很低。
在 64 位架构的机器上,一个切片需要 24 字节的内存:指针字段需要 8 字节,长度和容量字段分别需要 8 字节。由于与切片关联的数据包含在底层数组里,不属于切片本身,所以将切片复制到任意函数的时候,对底层数组大小都不会有影响。复制时只会复制切片本身,不会涉及底层数组。
第 78 页
切片、函数以及包含切片的结构类型这些类型由于具有引用语义,不能作为映射的键,使用这些类型会造成编译错误。
第 83 – 84 页
Go 语言是一种静态类型的编程语言,意味着编译器需要在编译时知晓程序里每个值的类型。
值的类型给编译器提供两部分信息:一,需要分配多少内存给这个值(即值的规模);二,这段内存表示什么。对于许多内置类型的情况来说,规模和表示是类型名的一部分。int64
类型的值需要 8 字节(64 位),表示一个整数值;float32
类型的值需要 4 字节(32 位),表示一个 IEEE-754 定义的二进制浮点数;bool
类型的值需要 1 字节(8 位),表示布尔值 true
和false
。
有些类型的内部表示与编译代码的机器的体系结构有关。例如,根据编译所在的机器的体系结构,一个 int
值的大小可能是 8 字节(64 位),也可能是 4 字节(32 位)。还要一些与体系结构相关的类型,如 Go 语言里的所有引用类型。
使用 var
创建一个变量并初始化其为零值。如果变量被初始化为某个非零值,就配合结构字面量和短变量声明操作符来创建变量。
一个短变量声明操作符在一次操作中完成两件事情:声明一个变量,并初始化。
第 88 页
Go 语言里有两种类型的接收者:值接收者和指针接收者。
第 90 – 92 页
Go 语言既允许使用值,也允许使用指针来调用方法,不必严格符合接收者的类型。这个支持非常方便开发者编写程序。
内置类型
分别是数值类型
、字符串类型
和布尔类型
。这些类型本质上是原始的类型。因此,当对这些值进行增加或者删除的时候,会创建一个新值。基于这个结论,当把这些类型的值传递给方法或者函数时,应该传递一个对应值的副本。
引用类型
有切片
、映射
、通道
、接口
和函数类型
。当声明上述类型的变量时,创建的变量被称为标头
(header)值。从技术细节上说,字符串也是一种引用类型。每个引用类型创建的标头值是包含一个指向底层数据结构的指针。每个引用类型还包含一组独特的字段,用于管理底层数据结构。因为标头值是为复制而设计的,所以永远不需要共享一个引用类型的值。标头值里包含一个指针,因此通过复制来传递一个引用类型的值的副本,本质上就是在共享底层数据结构。
第 122 页
Go 语言里的并发指的是能让某个函数独立于其他函数运行的能力。当一个函数创建为 goroutine 时,Go 会将其视为一个独立的工作单元。这个单元会被调度到可用的逻辑处理器上执行。Go 语言运行时的调度器是一个复杂的软件,能管理被创建的所有 goroutine 并为其分配执行时间。这个调度器在操作系统之上,将操作系统的线程与语言运行时的逻辑处理器绑定,并在逻辑处理器上运行 goroutine。调度器在任何给定的时间,都会全面控制哪个 goroutine 要在哪个逻辑处理器上运行。