mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-04 21:43:42 +00:00
commit
f3f18afffc
@ -1,7 +1,7 @@
|
||||
## 11.1. go test
|
||||
|
||||
go test命令是一个按照一定的约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀名的源文件并不是go build构建包的一部分,它们是go test测试的一部分。
|
||||
go test命令是一个按照一定的约定和组织来测试代码的程序。在包目录内,所有以`_test.go`为后缀名的源文件在执行go build时不会被构建成包的一部分,它们是go test测试的一部分。
|
||||
|
||||
在\*_test.go文件中,有三种类型的函数:测试函数、基准测试函数、示例函数。一个测试函数是以Test为函数名前缀的函数,用于测试程序的一些逻辑行为是否正确;go test命令会调用这些测试函数并报告测试结果是PASS或FAIL。基准测试函数是以Benchmark为函数名前缀的函数,它们用于衡量一些函数的性能;go test命令会多次运行基准函数以计算一个平均的执行时间。示例函数是以Example为函数名前缀的函数,提供一个由编译器保证正确性的示例文档。我们将在11.2节讨论测试函数的所有细节,病在11.4节讨论基准测试函数的细节,然后在11.6节讨论示例函数的细节。
|
||||
在`*_test.go`文件中,有三种类型的函数:测试函数、基准测试(benchmark)函数、示例函数。一个测试函数是以Test为函数名前缀的函数,用于测试程序的一些逻辑行为是否正确;go test命令会调用这些测试函数并报告测试结果是PASS或FAIL。基准测试函数是以Benchmark为函数名前缀的函数,它们用于衡量一些函数的性能;go test命令会多次运行基准函数以计算一个平均的执行时间。示例函数是以Example为函数名前缀的函数,提供一个由编译器保证正确性的示例文档。我们将在11.2节讨论测试函数的所有细节,并在11.4节讨论基准测试函数的细节,然后在11.6节讨论示例函数的细节。
|
||||
|
||||
go test命令会遍历所有的\*_test.go文件中符合上述命名规则的函数,然后生成一个临时的main包用于调用相应的测试函数,然后构建并运行、报告测试结果,最后清理测试中生成的临时文件。
|
||||
go test命令会遍历所有的`*_test.go`文件中符合上述命名规则的函数,生成一个临时的main包用于调用相应的测试函数,接着构建并运行、报告测试结果,最后清理测试中生成的临时文件。
|
||||
|
@ -16,7 +16,7 @@ func writeHeader(w io.Writer, contentType string) error {
|
||||
|
||||
因为Write方法需要传入一个byte切片而我们希望写入的值是一个字符串,所以我们需要使用[]byte(...)进行转换。这个转换分配内存并且做一个拷贝,但是这个拷贝在转换后几乎立马就被丢弃掉。让我们假装这是一个web服务器的核心部分并且我们的性能分析表示这个内存分配使服务器的速度变慢。这里我们可以避免掉内存分配么?
|
||||
|
||||
这个io.Writer接口告诉我们关于w持有的具体类型的唯一东西:就是可以向它写入字节切片。如果我们回顾net/http包中的内幕,我们知道在这个程序中的w变量持有的动态类型也有一个允许字符串高效写入的WriteString方法;这个方法会避免去分配一个零时的拷贝。(这可能像在黑夜中射击一样,但是许多满足io.Writer接口的重要类型同时也有WriteString方法,包括\*bytes.Buffer,\*os.File和\*bufio.Writer。)
|
||||
这个io.Writer接口告诉我们关于w持有的具体类型的唯一东西:就是可以向它写入字节切片。如果我们回顾net/http包中的内幕,我们知道在这个程序中的w变量持有的动态类型也有一个允许字符串高效写入的WriteString方法;这个方法会避免去分配一个临时的拷贝。(这可能像在黑夜中射击一样,但是许多满足io.Writer接口的重要类型同时也有WriteString方法,包括\*bytes.Buffer,\*os.File和\*bufio.Writer。)
|
||||
|
||||
我们不能对任意io.Writer类型的变量w,假设它也拥有WriteString方法。但是我们可以定义一个只有这个方法的新接口并且使用类型断言来检测是否w的动态类型满足这个新接口。
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
## 7.13. 类型开关
|
||||
|
||||
接口被以两种不同的方式使用。在第一个方式中,以io.Reader,io.Writer,fmt.Stringer,sort.Interface,http.Handler,和error为典型,一个接口的方法表达了实现这个接口的具体类型间的相思性,但是隐藏了代表的细节和这些具体类型本身的操作。重点在于方法上,而不是具体的类型上。
|
||||
接口被以两种不同的方式使用。在第一个方式中,以io.Reader,io.Writer,fmt.Stringer,sort.Interface,http.Handler,和error为典型,一个接口的方法表达了实现这个接口的具体类型间的相似性,但是隐藏了代表的细节和这些具体类型本身的操作。重点在于方法上,而不是具体的类型上。
|
||||
|
||||
第二个方式利用一个接口值可以持有各种具体类型值的能力并且将这个接口认为是这些类型的union(联合)。类型断言用来动态地区别这些类型并且对每一种情况都不一样。在这个方式中,重点在于具体的类型满足这个接口,而不是在于接口的方法(如果它确实有一些的话),并且没有任何的信息隐藏。我们将以这种方式使用的接口描述为discriminated unions(可辨识联合)。
|
||||
|
||||
|
@ -6,4 +6,4 @@
|
||||
|
||||
因为在Go语言中只有当两个或更多的类型实现一个接口时才使用接口,它们必定会从任意特定的实现细节中抽象出来。结果就是有更少和更简单方法(经常和io.Writer或 fmt.Stringer一样只有一个)的更小的接口。当新的类型出现时,小的接口更容易满足。对于接口设计的一个好的标准就是 ask only for what you need(只考虑你需要的东西)
|
||||
|
||||
我们完成了对methods和接口的学习过程。Go语言良好的支持面向对象风格的编程,但只不是说你仅仅只能使用它。不是任何事物都需要被当做成一个对象;独立的函数有它们自己的用处,未封装的数据类型也是这样。同时观察到这两个,在本书的前五章的例子中没有调用超过两打方法,像input.Scan,与之相反的是普遍的函数调用如fmt.Printf。
|
||||
我们完成了对methods和接口的学习过程。Go语言良好的支持面向对象风格的编程,但这不是说你仅仅只能使用它。不是任何事物都需要被当做成一个对象;独立的函数有它们自己的用处,未封装的数据类型也是这样。同时观察到这两个,在本书的前五章的例子中没有调用超过两打方法,像input.Scan,与之相反的是普遍的函数调用如fmt.Printf。
|
||||
|
Loading…
Reference in New Issue
Block a user