第7章,部分字词修订,语序调整。少量错误修订。

This commit is contained in:
zhliner
2017-08-24 22:29:24 +08:00
parent 9a9b9a0594
commit 17919273e1
14 changed files with 87 additions and 87 deletions

View File

@@ -2,9 +2,9 @@
目前为止,我们看到的类型都是具体的类型。一个具体的类型可以准确的描述它所代表的值,并且展示出对类型本身的一些操作方式:就像数字类型的算术操作,切片类型的取下标、添加元素和范围获取操作。具体的类型还可以通过它的内置方法提供额外的行为操作。总的来说,当你拿到一个具体的类型时你就知道它的本身是什么和你可以用它来做什么。
在Go语言中还存在着另外一种类型接口类型。接口类型是一种抽象的类型。它不会暴露出它所代表的对象的内部值的结构和这个对象支持的基础操作的集合它们只会展示出它们自己的方法。也就是说当你有看到一个接口类型的值时,你不知道它是什么,唯一知道的就是可以通过它的方法来做什么。
在Go语言中还存在着另外一种类型接口类型。接口类型是一种抽象的类型。它不会暴露出它所代表的对象的内部值的结构和这个对象支持的基础操作的集合它们只会表现出它们自己的方法。也就是说当你有看到一个接口类型的值时,你不知道它是什么,唯一知道的就是可以通过它的方法来做什么。
在本书中我们一直使用两个相似的函数来进行字符串的格式化fmt.Printf它会把结果写到标准输出和fmt.Sprintf它会把结果以字符串的形式返回。得益于使用接口我们不必可悲的因为返回结果在使用方式上的一些浅显不同就必需把格式化这个最困难的过程复制一份。实际上这两个函数都使用了另一个函数fmt.Fprintf来进行封装。fmt.Fprintf这个函数对它的计算结果会被怎么使用是完全不知道的。
在本书中我们一直使用两个相似的函数来进行字符串的格式化fmt.Printf它会把结果写到标准输出和fmt.Sprintf它会把结果以字符串的形式返回。得益于使用接口我们不必可悲的因为返回结果在使用方式上的一些浅显不同就必需把格式化这个最困难的过程复制一份。实际上这两个函数都使用了另一个函数fmt.Fprintf来进行封装。fmt.Fprintf这个函数对它的计算结果会被怎么使用是完全不知道的。
``` go
package fmt
@@ -23,7 +23,7 @@ func Sprintf(format string, args ...interface{}) string {
Fprintf的前缀F表示文件(File)也表明格式化输出结果应该被写入第一个参数提供的文件中。在Printf函数中的第一个参数os.Stdout是`*os.File`类型在Sprintf函数中的第一个参数&buf是一个指向可以写入字节的内存缓冲区然而它
并不是一个文件类型尽管它在某种意义上和文件类型相似。
即使Fprintf函数中的第一个参数也不是一个文件类型。它是io.Writer类型这是一个接口类型定义如下
即使Fprintf函数中的第一个参数也不是一个文件类型。它是io.Writer类型这是一个接口类型定义如下:
``` go
package io
@@ -43,9 +43,9 @@ type Writer interface {
io.Writer类型定义了函数Fprintf和这个函数调用者之间的约定。一方面这个约定需要调用者提供具体类型的值就像`*os.File`和`*bytes.Buffer`这些类型都有一个特定签名和行为的Write的函数。另一方面这个约定保证了Fprintf接受任何满足io.Writer接口的值都可以工作。Fprintf函数可能没有假定写入的是一个文件或是一段内存而是写入一个可以调用Write函数的值。
因为fmt.Fprintf函数没有对具体操作的值做任何假设而是仅仅通过io.Writer接口的约定来保证行为所以第一个参数可以安全地传入一个任何具体类型的值只需要满足io.Writer接口。一个类型可以自由的使用另一个满足相同接口的类型来进行替换被称作可替换性(LSP里氏替换)。这是一个面向对象的特征。
因为fmt.Fprintf函数没有对具体操作的值做任何假设而是仅仅通过io.Writer接口的约定来保证行为所以第一个参数可以安全地传入一个只需要满足io.Writer接口的任意具体类型的值。一个类型可以自由地被另一个满足相同接口的类型替换被称作可替换性(LSP里氏替换)。这是一个面向对象的特征。
让我们通过一个新的类型来进行校验,下面`*ByteCounter`类型里的Write方法仅仅在丢写向它的字节前统计它们的长度。(在这个+=赋值语句中让len(p)的类型和`*c`的类型匹配的转换是必须的。)
让我们通过一个新的类型来进行校验,下面`*ByteCounter`类型里的Write方法仅仅在丢写向它的字节前统计它们的长度。(在这个+=赋值语句中让len(p)的类型和`*c`的类型匹配的转换是必须的。)
<u><i>gopl.io/ch7/bytecounter</i></u>
```go
@@ -84,12 +84,12 @@ type Stringer interface {
我们会在7.10节解释fmt包怎么发现哪些值是满足这个接口类型的。
**练习 7.1** 使用来自ByteCounter的思路实现一个针对单词和行数的计数器。你会发现bufio.ScanWords非常的有用。
**练习 7.1** 使用来自ByteCounter的思路实现一个针对单词和行数的计数器。你会发现bufio.ScanWords非常的有用。
**练习 7.2** 写一个带有如下函数签名的函数CountingWriter传入一个io.Writer接口类型返回一个新的Writer类型把原来的Writer封装在里面和一个表示写入新的Writer字节数的int64类型指针
**练习 7.2** 写一个带有如下函数签名的函数CountingWriter传入一个io.Writer接口类型返回一个把原来的Writer封装在里面新的Writer类型和一个表示新的写入字节数的int64类型指针
```go
func CountingWriter(w io.Writer) (io.Writer, *int64)
```
**练习 7.3** 为在gopl.io/ch4/treesort (§4.4)的*tree类型实现一个String方法去展示tree类型的值序列。
**练习 7.3** 为在gopl.io/ch4/treesort (§4.4)的*tree类型实现一个String方法去展示tree类型的值序列。