从本篇文章开始,我们将一起探讨 Go 语言自带标准库中一些比较核心的代码包。这会涉及这些代码包的标准用法、使用禁忌、背后原理以及周边的知识。
在本篇文章,我会继续为你讲解更多更高级的测试方法。这会涉及testing包中更多的 API、go test命令支持的,更多标记更加复杂的测试结果,以及测试覆盖度分析等等。
人是否会进步以及进步得有多快,依赖的恰恰就是对自我的否定,这包括否定的深刻与否,以及否定自我的频率如何。这其实就是“不破不立”这个词表达的含义。
知识扩展
问题 1:怎样解释功能测试的测试结果?
我们先来看下面的测试命令和结果:
1 2
| $ go test puzzlers/article20/q2 ok puzzlers/article20/q2 0.008s
|
以$符号开头表明此行展现的是我输入的命令。在这里,我输入了go test puzzlers/article20/q2,这表示我想对导入路径为puzzlers/article20/q2的代码包进行测试。代码下面一行就是此次测试的简要结果。
panic 之中可以包含一个值,用于简要解释引发此 panic 的原因。
如果一个 panic 是我们在无意间引发的,那么其中的值只能由 Go 语言运行时系统给定。但是,当我们使用panic函数有意地引发一个 panic 的时候,却可以自行指定其包含的值。我们今天的第一个问题就是针对后一种情况提出的。
知识扩展
问题:怎样根据实际情况给予恰当的错误值?
我们已经知道,构建错误值体系的基本方式有两种,即:创建立体的错误类型体系和创建扁平的错误值列表。
先说错误类型体系。由于在 Go 语言中实现接口是非侵入式的,所以我们可以做得很灵活。比如,在标准库的net代码包中,有一个名为Error的接口类型。它算是内建接口类型error的一个扩展接口,因为error是net.Error的嵌入接口。
net.Error接口除了拥有error接口的Error方法之外,还有两个自己声明的方法:Timeout和Temporary。
Don’t communicate by sharing memory; share memory by communicating.
从 Go 语言编程的角度解释,这句话的意思就是:不要通过共享数据来通讯,恰恰相反,要以通讯的方式共享数据。
知识扩展
问题 1:怎样才能让主 goroutine 等待其他 goroutine?
一旦主 goroutine 中的代码执行完毕,当前的 Go 程序就会结束运行,无论其他的 goroutine 是否已经在运行了。那么,怎样才能做到等其他的 goroutine 运行完毕之后,再让主 goroutine 结束运行呢?
1 2 3 4 5 6 7
| type Dog struct { name string }
func (dog *Dog) SetName(name string) { dog.name = name }
|
对于基本类型Dog来说,*Dog就是它的指针类型。而对于一个Dog类型,值不为nil的变量dog,取址表达式&dog的结果就是该变量的值(也就是基本值)的指针值。
如果一个方法的接收者是*Dog类型的,那么该方法就是基本类型Dog的指针方法。
前导内容:正确使用接口的基础知识
在 Go 语言的语境中,当我们在谈论“接口”的时候,一定指的是接口类型。因为接口类型与其他数据类型不同,它是没法被实例化的。
更具体地说,我们既不能通过调用new函数或make函数创建出一个接口类型的值,也无法用字面量来表示一个接口类型的值。
对于某一个接口类型来说,如果没有任何数据类型可以作为它的实现,那么该接口的值就不可能存在。
结构体类型表示的是实实在在的数据结构。一个结构体类型可以包含若干个字段,每个字段通常都需要有确切的名字和类型。
前导内容:结构体类型基础知识
当然了,结构体类型也可以不包含任何字段,这样并不是没有意义的,因为我们还可以为类型关联上一些方法,这里你可以把方法看做是函数的特殊版本。
函数是独立的程序实体。我们可以声明有名字的函数,也可以声明没名字的函数,还可以把它们当做普通的值传来传去。我们能把具有相同签名的函数抽象成独立的函数类型,以作为一组输入、输出(或者说一类逻辑组件)的代表。