change escape of ch7

pull/11/head
Xargin 2016-10-18 13:20:38 +08:00
parent 9c768334f2
commit 3da62d2c3f
8 changed files with 14 additions and 14 deletions

View File

@ -20,7 +20,7 @@ func Sprintf(format string, args ...interface{}) string {
}
```
Fprintf的前缀F表示文件(File)也表明格式化输出结果应该被写入第一个参数提供的文件中。在Printf函数中的第一个参数os.Stdout是*os.File类型在Sprintf函数中的第一个参数&buf是一个指向可以写入字节的内存缓冲区然而它
Fprintf的前缀F表示文件(File)也表明格式化输出结果应该被写入第一个参数提供的文件中。在Printf函数中的第一个参数os.Stdout是`*os.File`类型在Sprintf函数中的第一个参数&buf是一个指向可以写入字节的内存缓冲区然而它
并不是一个文件类型尽管它在某种意义上和文件类型相似。
即使Fprintf函数中的第一个参数也不是一个文件类型。它是io.Writer类型这是一个接口类型定义如下
@ -41,11 +41,11 @@ type Writer interface {
}
```
io.Writer类型定义了函数Fprintf和这个函数调用者之间的约定。一方面这个约定需要调用者提供具体类型的值就像\*os.File和\*bytes.Buffer这些类型都有一个特定签名和行为的Write的函数。另一方面这个约定保证了Fprintf接受任何满足io.Writer接口的值都可以工作。Fprintf函数可能没有假定写入的是一个文件或是一段内存而是写入一个可以调用Write函数的值。
io.Writer类型定义了函数Fprintf和这个函数调用者之间的约定。一方面这个约定需要调用者提供具体类型的值就像`*os.File`和`*bytes.Buffer`这些类型都有一个特定签名和行为的Write的函数。另一方面这个约定保证了Fprintf接受任何满足io.Writer接口的值都可以工作。Fprintf函数可能没有假定写入的是一个文件或是一段内存而是写入一个可以调用Write函数的值。
因为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

View File

@ -74,7 +74,7 @@ func (f *celsiusFlag) Set(s string) error {
调用fmt.Sscanf函数从输入s中解析一个浮点数value和一个字符串unit。虽然通常必须检查Sscanf的错误返回但是在这个例子中我们不需要因为如果有错误发生就没有switch case会匹配到。
下面的CelsiusFlag函数将所有逻辑都封装在一起。它返回一个内嵌在celsiusFlag变量f中的Celsius指针给调用者。Celsius字段是一个会通过Set方法在标记处理的过程中更新的变量。调用Var方法将标记加入应用的命令行标记集合中有异常复杂命令行接口的全局变量flag.CommandLine.Programs可能有几个这个类型的变量。调用Var方法将一个*celsiusFlag参数赋值给一个flag.Value参数,导致编译器去检查*celsiusFlag是否有必须的方法。
下面的CelsiusFlag函数将所有逻辑都封装在一起。它返回一个内嵌在celsiusFlag变量f中的Celsius指针给调用者。Celsius字段是一个会通过Set方法在标记处理的过程中更新的变量。调用Var方法将标记加入应用的命令行标记集合中有异常复杂命令行接口的全局变量flag.CommandLine.Programs可能有几个这个类型的变量。调用Var方法将一个`*celsiusFlag`参数赋值给一个flag.Value参数,导致编译器去检查`*celsiusFlag`是否有必须的方法。
```go
// CelsiusFlag defines a Celsius flag with the specified name,

View File

@ -26,17 +26,17 @@ var w io.Writer
w.Write([]byte("hello")) // panic: nil pointer dereference
```
第二个语句将一个*os.File类型的值赋给变量w:
第二个语句将一个`*os.File`类型的值赋给变量w:
```go
w = os.Stdout
```
这个赋值过程调用了一个具体类型到接口类型的隐式转换这和显式的使用io.Writer(os.Stdout)是等价的。这类转换不管是显式的还是隐式的,都会刻画出操作到的类型和值。这个接口值的动态类型被设为*os.Stdout指针的类型描述符它的动态值持有os.Stdout的拷贝这是一个代表处理标准输出的os.File类型变量的指针图7.2)。
这个赋值过程调用了一个具体类型到接口类型的隐式转换这和显式的使用io.Writer(os.Stdout)是等价的。这类转换不管是显式的还是隐式的,都会刻画出操作到的类型和值。这个接口值的动态类型被设为`*os.Stdout`指针的类型描述符它的动态值持有os.Stdout的拷贝这是一个代表处理标准输出的os.File类型变量的指针图7.2)。
![](../images/ch7-02.png)
调用一个包含\*os.File类型指针的接口值的Write方法使得(\*os.File).Write方法被调用。这个调用输出“hello”。
调用一个包含`*os.File`类型指针的接口值的Write方法使得`(*os.File).Write`方法被调用。这个调用输出“hello”。
```go
w.Write([]byte("hello")) // "hello"

View File

@ -66,7 +66,7 @@ func length(s string) time.Duration {
}
```
printTracks函数将播放列表打印成一个表格。一个图形化的展示可能会更好点但是这个小程序使用text/tabwriter包来生成一个列是整齐对齐和隔开的表格像下面展示的这样。注意到*tabwriter.Writer是满足io.Writer接口的。它会收集每一片写向它的数据它的Flush方法会格式化整个表格并且将它写向os.Stdout标准输出
printTracks函数将播放列表打印成一个表格。一个图形化的展示可能会更好点但是这个小程序使用text/tabwriter包来生成一个列是整齐对齐和隔开的表格像下面展示的这样。注意到`*tabwriter.Writer`是满足io.Writer接口的。它会收集每一片写向它的数据它的Flush方法会格式化整个表格并且将它写向os.Stdout标准输出
```go
func printTracks(tracks []*Track) {

View File

@ -20,7 +20,7 @@ type errorString struct { text string }
func (e *errorString) Error() string { return e.text }
```
承载errorString的类型是一个结构体而非一个字符串这是为了保护它表示的错误避免粗心或有意的更新。并且因为是指针类型*errorString满足error接口而非errorString类型所以每个New函数的调用都分配了一个独特的和其他错误不相同的实例。我们也不想要重要的error例如io.EOF和一个刚好有相同错误消息的error比较后相等。
承载errorString的类型是一个结构体而非一个字符串这是为了保护它表示的错误避免粗心或有意的更新。并且因为是指针类型`*errorString`满足error接口而非errorString类型所以每个New函数的调用都分配了一个独特的和其他错误不相同的实例。我们也不想要重要的error例如io.EOF和一个刚好有相同错误消息的error比较后相等。
```go
fmt.Println(errors.New("EOF") == errors.New("EOF")) // "false"
@ -38,7 +38,7 @@ func Errorf(format string, args ...interface{}) error {
}
```
虽然*errorString可能是最简单的错误类型但远非只有它一个。例如syscall包提供了Go语言底层系统调用API。在多个平台上它定义一个实现error接口的数字类型Errno并且在Unix平台上Errno的Error方法会从一个字符串表中查找错误消息如下面展示的这样
虽然`*errorString`可能是最简单的错误类型但远非只有它一个。例如syscall包提供了Go语言底层系统调用API。在多个平台上它定义一个实现error接口的数字类型Errno并且在Unix平台上Errno的Error方法会从一个字符串表中查找错误消息如下面展示的这样
```go
package syscall

View File

@ -13,7 +13,7 @@ c := w.(*bytes.Buffer) // panic: interface holds *os.File, not *bytes.Buffer
第二种如果相反断言的类型T是一个接口类型然后类型断言检查是否x的动态类型满足T。如果这个检查成功了动态值没有获取到这个结果仍然是一个有相同类型和值部分的接口值但是结果有类型T。换句话说对一个接口类型的类型断言改变了类型的表述方式改变了可以获取的方法集合通常更大但是它保护了接口值内部的动态类型和值的部分。
在下面的第一个类型断言后w和rw都持有os.Stdout因此它们每个有一个动态类型*os.File但是变量w是一个io.Writer类型只对外公开出文件的Write方法然而rw变量也只公开它的Read方法。
在下面的第一个类型断言后w和rw都持有os.Stdout因此它们每个有一个动态类型`*os.File`但是变量w是一个io.Writer类型只对外公开出文件的Write方法然而rw变量也只公开它的Read方法。
```go
var w io.Writer
@ -38,7 +38,7 @@ f, ok := w.(*os.File) // success: ok, f == os.Stdout
b, ok := w.(*bytes.Buffer) // failure: !ok, b == nil
```
第二个结果常规地赋值给一个命名为ok的变量。如果这个操作失败了那么ok就是false值第一个结果等于被断言类型的零值在这个例子中就是一个nil的*bytes.Buffer类型。
第二个结果常规地赋值给一个命名为ok的变量。如果这个操作失败了那么ok就是false值第一个结果等于被断言类型的零值在这个例子中就是一个nil的`*bytes.Buffer`类型。
这个ok结果经常立即用于决定程序下面做什么。if语句的扩展格式让这个变的很简洁

View File

@ -48,7 +48,7 @@ fmt.Printf("%#v\n", err)
// &os.PathError{Op:"open", Path:"/no/such/file", Err:0x2}
```
这就是三个帮助函数是怎么工作的。例如下面展示的IsNotExist它会报出是否一个错误和syscall.ENOENT(§7.8)或者和有名的错误os.ErrNotExist相等(可以在§5.4.2中找到io.EOF或者是一个*PathError它内部的错误是syscall.ENOENT和os.ErrNotExist其中之一。
这就是三个帮助函数是怎么工作的。例如下面展示的IsNotExist它会报出是否一个错误和syscall.ENOENT(§7.8)或者和有名的错误os.ErrNotExist相等(可以在§5.4.2中找到io.EOF或者是一个`*PathError`它内部的错误是syscall.ENOENT和os.ErrNotExist其中之一。
```go
import (

View File

@ -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的动态类型满足这个新接口。