diff --git a/eBook/12.0.md b/eBook/12.0.md
index 7e569fd4d..5ce856413 100644
--- a/eBook/12.0.md
+++ b/eBook/12.0.md
@@ -1,6 +1,6 @@
# 12.0 读写数据
-除了 fmt 和 os 包,我们还需要用到 bufio 包来处理缓冲的输入和输出。
+除了 `fmt` 和 `os` 包,我们还需要用到 `bufio` 包来处理缓冲的输入和输出。
## 链接
diff --git a/eBook/12.1.md b/eBook/12.1.md
index f07fe018e..ad166da76 100644
--- a/eBook/12.1.md
+++ b/eBook/12.1.md
@@ -1,6 +1,6 @@
# 12.1 读取用户的输入
-我们如何读取用户的键盘(控制台)输入呢?从键盘和标准输入 `os.Stdin` 读取输入,最简单的办法是使用 `fmt` 包提供的 Scan 和 Sscan 开头的函数。请看以下程序:
+我们如何读取用户的键盘(控制台)输入呢?从键盘和标准输入 `os.Stdin` 读取输入,最简单的办法是使用 `fmt` 包提供的 `Scan...` 和 `Sscan...` 开头的函数。请看以下程序:
示例 12.1 [readinput1.go](examples/chapter_12/readinput1.go):
@@ -28,9 +28,9 @@ func main() {
}
```
-`Scanln` 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。`Scanf` 与其类似,除了 `Scanf` 的第一个参数用作格式字符串,用来决定如何读取。`Sscan` 和以 `Sscan` 开头的函数则是从字符串读取,除此之外,与 `Scanf` 相同。如果这些函数读取到的结果与您预想的不同,您可以检查成功读入数据的个数和返回的错误。
+`Scanln()` 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。`Scanf()` 与其类似,除了 `Scanf()` 的第一个参数用作格式字符串,用来决定如何读取。`Sscan...` 和以 `Sscan...` 开头的函数则是从字符串读取,除此之外,与 `Scanf()` 相同。如果这些函数读取到的结果与您预想的不同,您可以检查成功读入数据的个数和返回的错误。
-您也可以使用 `bufio` 包提供的缓冲读取(buffered reader)来读取数据,正如以下例子所示:
+您也可以使用 `bufio` 包提供的缓冲读取器 (buffered reader) 来读取数据,正如以下例子所示:
示例 12.2 [readinput2.go](examples/chapter_12/readinput2.go):
@@ -60,13 +60,13 @@ func main() {
`bufio.NewReader()` 构造函数的签名为:`func NewReader(rd io.Reader) *Reader`
-该函数的实参可以是满足 `io.Reader` 接口的任意对象(任意包含有适当的 `Read()` 方法的对象,请参考[章节11.8](11.8.md)),函数返回一个新的带缓冲的 `io.Reader` 对象,它将从指定读取器(例如 `os.Stdin`)读取内容。
+该函数的实参可以是满足 `io.Reader` 接口的任意对象(任意包含有适当的 `Read()` 方法的对象,请参考[章节 11.8](11.8.md)),函数返回一个新的带缓冲的 `io.Reader` 对象,它将从指定读取器(例如 `os.Stdin`)读取内容。
返回的读取器对象提供一个方法 `ReadString(delim byte)`,该方法从输入中读取内容,直到碰到 `delim` 指定的字符,然后将读取到的内容连同 `delim` 字符一起放到缓冲区。
`ReadString` 返回读取到的字符串,如果碰到错误则返回 `nil`。如果它一直读到文件结束,则返回读取到的字符串和 `io.EOF`。如果读取过程中没有碰到 `delim` 字符,将返回错误 `err != nil`。
-在上面的例子中,我们会读取键盘输入,直到回车键(\n)被按下。
+在上面的例子中,我们会读取键盘输入,直到回车键 (`\n`) 被按下。
屏幕是标准输出 `os.Stdout`;`os.Stderr` 用于显示错误信息,大多数情况下等同于 `os.Stdout`。
@@ -133,15 +133,15 @@ func main() {
**练习 12.1:** [word_letter_count.go](exercises/chapter_12/word_letter_count.go)
编写一个程序,从键盘读取输入。当用户输入 'S' 的时候表示输入结束,这时程序输出 3 个数字:
-i) 输入的字符的个数,包括空格,但不包括 '\r' 和 '\n'
+i) 输入的字符的个数,包括空格,但不包括 `'\r'` 和 `'\n'`
ii) 输入的单词的个数
iii) 输入的行数
**练习 12.2:** [calculator.go](exercises/chapter_12/calculator.go)
编写一个简单的逆波兰式计算器,它接受用户输入的整型数(最大值 999999)和运算符 +、-、\*、/。
-输入的格式为:number1 ENTER number2 ENTER operator ENTER --> 显示结果
-当用户输入字符 'q' 时,程序结束。请使用您在练习11.13中开发的 `stack` 包。
+输入的格式为:`number1 ENTER number2 ENTER operator ENTER --> 显示结果`
+当用户输入字符 `'q'` 时,程序结束。请使用您在[练习 11.13](11.12.md) 中开发的 `stack` 包。
## 链接
diff --git a/eBook/12.10.md b/eBook/12.10.md
index cd471cf09..986f35dae 100644
--- a/eBook/12.10.md
+++ b/eBook/12.10.md
@@ -1,6 +1,6 @@
# 12.10 XML 数据格式
-下面是与 12.9 节 JSON 例子等价的 XML 版本:
+下面是与 [12.9 节](12.9.md) JSON 例子等价的 XML 版本:
```xml
@@ -9,11 +9,11 @@
```
-如同 json 包一样,也有 `xml.Marshal()` 和 `xml.Unmarshal()` 从 XML 中编码和解码数据;但这个更通用,可以从文件中读取和写入(或者任何实现了 io.Reader 和 io.Writer 接口的类型)
+如同 `json` 包一样,也有 `xml.Marshal()` 和 `xml.Unmarshal()` 从 XML 中编码和解码数据;但这个更通用,可以从文件中读取和写入(或者任何实现了 `io.Reader` 和 `io.Writer` 接口的类型)
和 JSON 的方式一样,XML 数据可以序列化为结构,或者从结构反序列化为 XML 数据;这些可以在例子 15.8([twitter_status.go](examples/chapter_15/twitter_status.go))中看到。
-encoding/xml 包实现了一个简单的 XML 解析器(SAX),用来解析 XML 数据内容。下面的例子说明如何使用解析器:
+`encoding`/`xml` 包实现了一个简单的 XML 解析器(SAX),用来解析 XML 数据内容。下面的例子说明如何使用解析器:
示例 12.17 [xml.go](examples/chapter_12/xml.go):
@@ -74,9 +74,9 @@ End of token
包中定义了若干 XML 标签类型:StartElement,Chardata(这是从开始标签到结束标签之间的实际文本),EndElement,Comment,Directive 或 ProcInst。
-包中同样定义了一个结构解析器:`NewParser` 方法持有一个 io.Reader(这里具体类型是 strings.NewReader)并生成一个解析器类型的对象。还有一个 `Token()` 方法返回输入流里的下一个 XML token。在输入流的结尾处,会返回(nil,io.EOF)
+包中同样定义了一个结构解析器:`NewParser()` 方法持有一个 `io.Reader`(这里具体类型是 `strings.NewReader`)并生成一个解析器类型的对象。还有一个 `Token()` 方法返回输入流里的下一个 XML token。在输入流的结尾处,会返回 (`nil`,`io.EOF`)
-XML 文本被循环处理直到 `Token()` 返回一个错误,因为已经到达文件尾部,再没有内容可供处理了。通过一个 type-switch 可以根据一些 XML 标签进一步处理。Chardata 中的内容只是一个 []byte,通过字符串转换让其变得可读性强一些。
+XML 文本被循环处理直到 `Token()` 返回一个错误,因为已经到达文件尾部,再没有内容可供处理了。通过一个 type-switch 可以根据一些 XML 标签进一步处理。Chardata 中的内容只是一个 `[]byte`,通过字符串转换让其变得可读性强一些。
## 链接
diff --git a/eBook/12.11.md b/eBook/12.11.md
index 6176181c5..2a6d3d242 100644
--- a/eBook/12.11.md
+++ b/eBook/12.11.md
@@ -2,7 +2,7 @@
Gob 是 Go 自己的以二进制形式序列化和反序列化程序数据的格式;可以在 `encoding` 包中找到。这种格式的数据简称为 Gob (即 Go binary 的缩写)。类似于 Python 的 "pickle" 和 Java 的 "Serialization"。
-Gob 通常用于远程方法调用(RPCs,参见 [15.9节](15.9.md) 的 rpc 包)参数和结果的传输,以及应用程序和机器之间的数据传输。
+Gob 通常用于远程方法调用(RPCs,参见 [15.9 节](15.9.md)的 `rpc` 包)参数和结果的传输,以及应用程序和机器之间的数据传输。
它和 JSON 或 XML 有什么不同呢?Gob 特定地用于纯 Go 的环境中,例如,两个用 Go 写的服务之间的通信。这样的话服务可以被实现得更加高效和优化。
Gob 不是可外部定义,语言无关的编码方式。因此它的首选格式是二进制,而不是像 JSON 和 XML 那样的文本格式。
Gob 并不是一种不同于 Go 的语言,而是在编码和解码过程中用到了 Go 的反射。
@@ -25,7 +25,7 @@ type U struct { X, Y *int8 }
var u U
```
-在接收者中,X 的值是7,Y 的值是0(Y的值并没有从 t 中传递过来,因为它是零值)
+在接收者中,`X` 的值是 `7`,`Y` 的值是 `0`(`Y` 的值并没有从 `t` 中传递过来,因为它是零值)
和 JSON 的使用方式一样,Gob 使用通用的 `io.Writer` 接口,通过 `NewEncoder()` 函数创建 `Encoder` 对象并调用 `Encode()`;相反的过程使用通用的 `io.Reader` 接口,通过 `NewDecoder()` 函数创建 `Decoder` 对象并调用 `Decode()`。
diff --git a/eBook/12.12.md b/eBook/12.12.md
index ef16a3b2a..b01651f58 100644
--- a/eBook/12.12.md
+++ b/eBook/12.12.md
@@ -73,7 +73,7 @@ type Hash interface {
}
```
-通过 io.WriteString 或 hasher.Write 将给定的 []byte 附加到当前的 `hash.Hash` 对象中。
+通过 `io.WriteString` 或 `hasher.Write` 将给定的 `[]byte` 附加到当前的 `hash.Hash` 对象中。
**练习 12.9**:[hash_md5.go](exercises/chapter_12/hash_md5.go):
diff --git a/eBook/12.2.md b/eBook/12.2.md
index 28a0a0f73..b0cc534c2 100644
--- a/eBook/12.2.md
+++ b/eBook/12.2.md
@@ -37,15 +37,15 @@ func main() {
}
```
-变量 `inputFile` 是 `*os.File` 类型的。该类型是一个结构,表示一个打开文件的描述符(文件句柄)。然后,使用 `os` 包里的 `Open` 函数来打开一个文件。该函数的参数是文件名,类型为 `string`。在上面的程序中,我们以只读模式打开 `input.dat` 文件。
+变量 `inputFile` 是 `*os.File` 类型的。该类型是一个结构,表示一个打开文件的描述符(文件句柄)。然后,使用 `os` 包里的 `Open()` 函数来打开一个文件。该函数的参数是文件名,类型为 `string`。在上面的程序中,我们以只读模式打开 `input.dat` 文件。
-如果文件不存在或者程序没有足够的权限打开这个文件,Open函数会返回一个错误:`inputFile, inputError = os.Open("input.dat")`。如果文件打开正常,我们就使用 `defer inputFile.Close()` 语句确保在程序退出前关闭该文件。然后,我们使用 `bufio.NewReader` 来获得一个读取器变量。
+如果文件不存在或者程序没有足够的权限打开这个文件,Open函数会返回一个错误:`inputFile, inputError = os.Open("input.dat")`。如果文件打开正常,我们就使用 `defer inputFile.Close()` 语句确保在程序退出前关闭该文件。然后,我们使用 `bufio.NewReader()` 来获得一个读取器变量。
-通过使用 `bufio` 包提供的读取器(写入器也类似),如上面程序所示,我们可以很方便的操作相对高层的 string 对象,而避免了去操作比较底层的字节。
+通过使用 `bufio` 包提供的读取器(写入器也类似),如上面程序所示,我们可以很方便的操作相对高层的 `string` 对象,而避免了去操作比较底层的字节。
-接着,我们在一个无限循环中使用 `ReadString('\n')` 或 `ReadBytes('\n')` 将文件的内容逐行(行结束符 '\n')读取出来。
+接着,我们在一个无限循环中使用 `ReadString('\n')` 或 `ReadBytes('\n')` 将文件的内容逐行(行结束符 `'\n'`)读取出来。
-**注意:** 在之前的例子中,我们看到,Unix 和 Linux 的行结束符是 \n,而 Windows 的行结束符是 \r\n。在使用 `ReadString` 和 `ReadBytes` 方法的时候,我们不需要关心操作系统的类型,直接使用 \n 就可以了。另外,我们也可以使用 `ReadLine()` 方法来实现相同的功能。
+**注意:** 在之前的例子中,我们看到,Unix 和 Linux 的行结束符是 `\n`,而 Windows 的行结束符是 `\r\n`。在使用 `ReadString` 和 `ReadBytes` 方法的时候,我们不需要关心操作系统的类型,直接使用 `\n` 就可以了。另外,我们也可以使用 `ReadLine()` 方法来实现相同的功能。
一旦读取到文件末尾,变量 `readerError` 的值将变成非空(事实上,其值为常量 `io.EOF`),我们就会执行 `return` 语句从而退出循环。
@@ -53,7 +53,7 @@ func main() {
**1) 将整个文件的内容读到一个字符串里:**
-如果您想这么做,可以使用 `io/ioutil` 包里的 `ioutil.ReadFile()` 方法,该方法第一个返回值的类型是 `[]byte`,里面存放读取到的内容,第二个返回值是错误,如果没有错误发生,第二个返回值为 nil。请看示例 12.5。类似的,函数 `WriteFile()` 可以将 `[]byte` 的值写入文件。
+如果您想这么做,可以使用 `io/ioutil` 包里的 `ioutil.ReadFile()` 方法,该方法第一个返回值的类型是 `[]byte`,里面存放读取到的内容,第二个返回值是错误,如果没有错误发生,第二个返回值为 `nil`。请看示例 12.5。类似的,函数 `WriteFile()` 可以将 `[]byte` 的值写入文件。
示例 12.5 [read_write_file1.go](examples/chapter_12/read_write_file1.go):
@@ -83,7 +83,7 @@ func main() {
**2) 带缓冲的读取**
-在很多情况下,文件的内容是不按行划分的,或者干脆就是一个二进制文件。在这种情况下,`ReadString()`就无法使用了,我们可以使用 `bufio.Reader` 的 `Read()`,它只接收一个参数:
+在很多情况下,文件的内容是不按行划分的,或者干脆就是一个二进制文件。在这种情况下,`ReadString()` 就无法使用了,我们可以使用 `bufio.Reader` 的 `Read()`,它只接收一个参数:
```go
buf := make([]byte, 1024)
@@ -92,11 +92,11 @@ n, err := inputReader.Read(buf)
if (n == 0) { break}
```
-变量 n 的值表示读取到的字节数.
+变量 `n` 的值表示读取到的字节数.
**3) 按列读取文件中的数据**
-如果数据是按列排列并用空格分隔的,你可以使用 `fmt` 包提供的以 FScan 开头的一系列函数来读取他们。请看以下程序,我们将 3 列的数据分别读入变量 v1、v2 和 v3 内,然后分别把他们添加到切片的尾部。
+如果数据是按列排列并用空格分隔的,你可以使用 `fmt` 包提供的以 `FScan...` 开头的一系列函数来读取他们。请看以下程序,我们将 3 列的数据分别读入变量 `v1`、`v2` 和 `v3` 内,然后分别把他们添加到切片的尾部。
示例 12.6 [read_file2.go](examples/chapter_12/read_file2.go):
@@ -141,7 +141,7 @@ func main() {
[150 280 356]
```
-**注意:** `path` 包里包含一个子包叫 `filepath`,这个子包提供了跨平台的函数,用于处理文件名和路径。例如 Base() 函数用于获得路径中的最后一个元素(不包含后面的分隔符):
+**注意:** `path` 包里包含一个子包叫 `filepath`,这个子包提供了跨平台的函数,用于处理文件名和路径。例如 `Base()` 函数用于获得路径中的最后一个元素(不包含后面的分隔符):
```go
import "path/filepath"
@@ -158,13 +158,13 @@ filename := filepath.Base(path)
"Go for It";45.9;356
"The Go Way";55;500
```
-每行的第一个字段为 title,第二个字段为 price,第三个字段为 quantity。内容的格式基本与 示例 12.3c 的相同,除了分隔符改成了分号。请读取出文件的内容,创建一个结构用于存取一行的数据,然后使用结构的切片,并把数据打印出来。
+每行的第一个字段为标题,第二个字段为价格,第三个字段为数量。内容的格式基本与 示例 12.3c 的相同,除了分隔符改成了分号。请读取出文件的内容,创建一个结构用于存取一行的数据,然后使用结构的切片,并把数据打印出来。
关于解析 CSV 文件,`encoding/csv` 包提供了相应的功能。具体请参考 [http://golang.org/pkg/encoding/csv/](http://golang.org/pkg/encoding/csv/) 。
-## 12.2.2 `compress`包:读取压缩文件
+## 12.2.2 compress 包:读取压缩文件
-`compress`包提供了读取压缩文件的功能,支持的压缩文件格式为:bzip2、flate、gzip、lzw 和 zlib。
+`compress` 包提供了读取压缩文件的功能,支持的压缩文件格式为:bzip2、flate、gzip、lzw 和 zlib。
下面的程序展示了如何读取一个 gzip 文件。
@@ -251,7 +251,7 @@ func main () {
outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)
```
-可以看到,`OpenFile` 函数有三个参数:文件名、一个或多个标志(使用逻辑运算符“|”连接),使用的文件权限。
+可以看到,`OpenFile` 函数有三个参数:文件名、一个或多个标志(使用逻辑运算符 `|` 连接),使用的文件权限。
我们通常会用到以下标志:
@@ -260,7 +260,7 @@ outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 06
- `os.O_CREATE`:创建:如果指定文件不存在,就创建该文件。
- `os.O_TRUNC`:截断:如果指定文件已存在,就将该文件的长度截为 0 。
-在读文件的时候,文件的权限是被忽略的,所以在使用 `OpenFile` 时传入的第三个参数可以用 0 。而在写文件时,不管是 Unix 还是 Windows,都需要使用 0666。
+在读文件的时候,文件的权限是被忽略的,所以在使用 `OpenFile()` 时传入的第三个参数可以用 0 。而在写文件时,不管是 Unix 还是 Windows,都需要使用 `0666`。
然后,我们创建一个写入器(缓冲区)对象:
@@ -268,13 +268,13 @@ outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 06
outputWriter := bufio.NewWriter(outputFile)
```
-接着,使用一个 for 循环,将字符串写入缓冲区,写 10 次:`outputWriter.WriteString(outputString)`
+接着,使用一个 `for` 循环,将字符串写入缓冲区,写 10 次:`outputWriter.WriteString(outputString)`
缓冲区的内容紧接着被完全写入文件:`outputWriter.Flush()`
-如果写入的东西很简单,我们可以使用 `fmt.Fprintf(outputFile, "Some test data.\n")` 直接将内容写入文件。`fmt` 包里的 F 开头的 Print 函数可以直接写入任何 `io.Writer`,包括文件(请参考[章节12.8](12.8.md))。
+如果写入的东西很简单,我们可以使用 `fmt.Fprintf(outputFile, "Some test data.\n")` 直接将内容写入文件。`fmt` 包里的 `F...` 开头的 `Print()` 函数可以直接写入任何 `io.Writer`,包括文件(请参考[章节 12.8](12.8.md))。
-程序 `filewrite.go` 展示了不使用 `fmt.FPrintf` 函数,使用其他函数如何写文件:
+程序 `filewrite.go` 展示了不使用 `fmt.FPrintf()` 函数,使用其他函数如何写文件:
示例 12.8 [filewrite.go](examples/chapter_12/filewrite.go):
@@ -293,13 +293,13 @@ func main() {
使用 `os.Stdout.WriteString("hello, world\n")`,我们可以输出到屏幕。
-我们以只写模式创建或打开文件"test",并且忽略了可能发生的错误:`f, _ := os.OpenFile("test", os.O_CREATE|os.O_WRONLY, 0666)`
+我们以只写模式创建或打开文件 `"test"` ,并且忽略了可能发生的错误:`f, _ := os.OpenFile("test", os.O_CREATE|os.O_WRONLY, 0666)`
-我们不使用缓冲区,直接将内容写入文件:`f.WriteString( )`
+我们不使用缓冲区,直接将内容写入文件:`f.WriteString()`
**练习 12.4**:[wiki_part1.go](exercises/chapter_12/wiki_part1.go)
-(这是一个独立的练习,但是同时也是为[章节15.4](15.4.md)做准备)
+(这是一个独立的练习,但是同时也是为[章节 15.4](15.4.md) 做准备)
程序中的数据结构如下,是一个包含以下字段的结构:
@@ -310,9 +310,9 @@ type Page struct {
}
```
-请给这个结构编写一个 `save` 方法,将 Title 作为文件名、Body 作为文件内容,写入到文本文件中。
+请给这个结构编写一个 `save()` 方法,将 Title 作为文件名、Body 作为文件内容,写入到文本文件中。
-再编写一个 `load` 函数,接收的参数是字符串 title,该函数读取出与 title 对应的文本文件。请使用 `*Page` 做为参数,因为这个结构可能相当巨大,我们不想在内存中拷贝它。请使用 `ioutil` 包里的函数(参考章节12.2.1)。
+再编写一个 `load()` 函数,接收的参数是字符串 `title`,该函数读取出与 `title` 对应的文本文件。请使用 `*Page` 做为参数,因为这个结构可能相当巨大,我们不想在内存中拷贝它。请使用 `ioutil` 包里的函数(参考[章节 12.2.1](12.2.md))。
## 链接
diff --git a/eBook/12.3.md b/eBook/12.3.md
index b27048573..1dfd26995 100644
--- a/eBook/12.3.md
+++ b/eBook/12.3.md
@@ -1,6 +1,6 @@
# 12.3 文件拷贝
-如何拷贝一个文件到另一个文件?最简单的方式就是使用 io 包:
+如何拷贝一个文件到另一个文件?最简单的方式就是使用 `io` 包:
示例 12.10 [filecopy.go](examples/chapter_12/filecopy.go):
@@ -36,7 +36,7 @@ func CopyFile(dstName, srcName string) (written int64, err error) {
}
```
-注意 `defer` 的使用:当打开 dst 文件时发生了错误,那么 `defer` 仍然能够确保 `src.Close()` 执行。如果不这么做,src 文件会一直保持打开状态并占用资源。
+注意 `defer` 的使用:当打开 `dst` 文件时发生了错误,那么 `defer` 仍然能够确保 `src.Close()` 执行。如果不这么做,`src` 文件会一直保持打开状态并占用资源。
## 链接
diff --git a/eBook/12.4.md b/eBook/12.4.md
index 913be1b5d..1bf110fdd 100644
--- a/eBook/12.4.md
+++ b/eBook/12.4.md
@@ -2,7 +2,7 @@
## 12.4.1 os 包
-os 包中有一个 string 类型的切片变量 `os.Args`,用来处理一些基本的命令行参数,它在程序启动后读取命令行输入的参数。来看下面的打招呼程序:
+`os` 包中有一个 `string` 类型的切片变量 `os.Args`,用来处理一些基本的命令行参数,它在程序启动后读取命令行输入的参数。来看下面的打招呼程序:
示例 12.11 [os_args.go](examples/chapter_12/os_args.go):
@@ -35,13 +35,13 @@ func main() {
**练习 12.5**:[hello_who.go](exercises/chapter_12/hello_who.go)
-写一个"Hello World"的变种程序:把人的名字作为程序命令行执行的一个参数,比如: `hello_who Evan Michael Laura` 那么会输出 `Hello Evan Michael Laura!`
+写一个“Hello World”的变种程序:把人的名字作为程序命令行执行的一个参数,比如: `hello_who Evan Michael Laura` 那么会输出 `Hello Evan Michael Laura!`
## 12.4.2 flag 包
-flag 包有一个扩展功能用来解析命令行选项。但是通常被用来替换基本常量,例如,在某些情况下我们希望在命令行给常量一些不一样的值。(参看 19 章的项目)
+`flag` 包有一个扩展功能用来解析命令行选项。但是通常被用来替换基本常量,例如,在某些情况下我们希望在命令行给常量一些不一样的值。(参看 [19 章](19.0.md)的项目)
-在 flag 包中有一个 Flag 被定义成一个含有如下字段的结构体:
+在 `flag` 包中有一个 `Flag` 是被定义成一个含有如下字段的结构体:
```go
type Flag struct {
@@ -89,7 +89,7 @@ func main() {
`flag.Parse()` 扫描参数列表(或者常量列表)并设置 flag, `flag.Arg(i)` 表示第 i 个参数。`Parse()` 之后 `flag.Arg(i)` 全部可用,`flag.Arg(0)` 就是第一个真实的 flag,而不是像 `os.Args(0)` 放置程序的名字。
`flag.Narg()` 返回参数的数量。解析后 flag 或常量就可用了。
-`flag.Bool()` 定义了一个默认值是 `false` 的 flag:当在命令行出现了第一个参数(这里是 "n"),flag 被设置成 `true`(NewLine 是 `*bool` 类型)。flag 被解引用到 `*NewLine`,所以当值是 `true` 时将添加一个 Newline("\n")。
+`flag.Bool()` 定义了一个默认值是 `false` 的 flag:当在命令行出现了第一个参数(这里是 `'n'`),flag 被设置成 `true`(`NewLine` 是 `*bool` 类型)。flag 被解引用到 `*NewLine`,所以当值是 `true` 时将添加一个 `Newline("\n")`。
`flag.PrintDefaults()` 打印 flag 的使用帮助信息,本例中打印的是:
@@ -97,9 +97,9 @@ func main() {
-n=false: print newline
```
-`flag.VisitAll(fn func(*Flag))` 是另一个有用的功能:按照字典顺序遍历 flag,并且对每个标签调用 fn (参考 15.8 章的例子)
+`flag.VisitAll(fn func(*Flag))` 是另一个有用的功能:按照字典顺序遍历 flag,并且对每个标签调用 fn (参考 [15.8 章](15.8.md)的例子)
-当在命令行(Windows)中执行:`echo.exe A B C`,将输出:`A B C`;执行 `echo.exe -n A B C`,将输出:
+当在命令行 (Windows) 中执行:`echo.exe A B C`,将输出:`A B C`;执行 `echo.exe -n A B C`,将输出:
```
A
@@ -125,7 +125,7 @@ if *processedFlag { // found flag -proc
要给 flag 定义其它类型,可以使用 `flag.Int()`,`flag.Float64()`,`flag.String()`。
-在第 15.8 章你将找到一个具体的例子。
+在[第 15.8 章](15.8.md)你将找到一个具体的例子。
## 链接
diff --git a/eBook/12.5.md b/eBook/12.5.md
index 0b729ad5d..dc50b4a97 100644
--- a/eBook/12.5.md
+++ b/eBook/12.5.md
@@ -45,11 +45,11 @@ func main() {
}
```
-在 12.6 章节,我们将看到如何使用缓冲写入。
+在 [12.6 章节](12.6.md),我们将看到如何使用缓冲写入。
**练习 12.6**:[cat_numbered.go](exercises/chapter_12/cat_numbered.go)
-扩展 cat.go 例子,使用 flag 添加一个选项,目的是为每一行头部加入一个行号。使用 `cat -n test` 测试输出。
+扩展 [cat.go](exercises/chapter_12/cat.go) 例子,使用 flag 添加一个选项,目的是为每一行头部加入一个行号。使用 `cat -n test` 测试输出。
## 链接
diff --git a/eBook/12.6.md b/eBook/12.6.md
index 934abf06b..6d4518c24 100644
--- a/eBook/12.6.md
+++ b/eBook/12.6.md
@@ -1,6 +1,6 @@
# 12.6 用切片读写文件
-切片提供了 Go 中处理 I/O 缓冲的标准方式,下面 `cat` 函数的第二版中,在一个切片缓冲内使用无限 for 循环(直到文件尾部 EOF)读取文件,并写入到标准输出(`os.Stdout`)。
+切片提供了 Go 中处理 I/O 缓冲的标准方式,下面 `cat` 函数的第二版中,在一个切片缓冲内使用无限 `for` 循环(直到文件尾部 `EOF`)读取文件,并写入到标准输出(`os.Stdout`)。
```go
func cat(f *os.File) {
diff --git a/eBook/12.7.md b/eBook/12.7.md
index 2dcfb5eb3..784c4a9d5 100644
--- a/eBook/12.7.md
+++ b/eBook/12.7.md
@@ -1,6 +1,6 @@
# 12.7 用 defer 关闭文件
-`defer` 关键字(参看 6.4)对于在函数结束时关闭打开的文件非常有用,例如下面的代码片段:
+`defer` 关键字(参看 [6.4](06.4.md))对于在函数结束时关闭打开的文件非常有用,例如下面的代码片段:
```go
func data(name string) string {
@@ -11,7 +11,7 @@ func data(name string) string {
}
```
-在函数 return 后执行了 `f.Close()`
+在函数 `return` 后执行了 `f.Close()`
## 链接
diff --git a/eBook/12.8.md b/eBook/12.8.md
index 6e6e3aa92..2cd9a08d6 100644
--- a/eBook/12.8.md
+++ b/eBook/12.8.md
@@ -1,6 +1,6 @@
# 12.8 使用接口的实际例子:fmt.Fprintf
-例子程序 `io_interfaces.go` 很好的阐述了 io 包中的接口概念。
+例子程序 `io_interfaces.go` 很好的阐述了 `io` 包中的接口概念。
示例 12.15 [io_interfaces.go](examples/chapter_12/io_interfaces.go):
@@ -38,7 +38,7 @@ hello world! - buffered
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
```
-不是写入一个文件,而是写入一个 `io.Writer` 接口类型的变量,下面是 `Writer` 接口在 io 包中的定义:
+不是写入一个文件,而是写入一个 `io.Writer` 接口类型的变量,下面是 `Writer` 接口在 `io` 包中的定义:
```go
type Writer interface {
@@ -46,9 +46,9 @@ type Writer interface {
}
```
-`fmt.Fprintf()` 依据指定的格式向第一个参数内写入字符串,第一个参数必须实现了 `io.Writer` 接口。`Fprintf()` 能够写入任何类型,只要其实现了 `Write` 方法,包括 `os.Stdout`,文件(例如 os.File),管道,网络连接,通道等等,同样的也可以使用 bufio 包中缓冲写入。bufio 包中定义了 `type Writer struct{...}` 。
+`fmt.Fprintf()` 依据指定的格式向第一个参数内写入字符串,第一个参数必须实现了 `io.Writer` 接口。`Fprintf()` 能够写入任何类型,只要其实现了 `Write` 方法,包括 `os.Stdout`,文件(例如 `os.File`),管道,网络连接,通道等等。同样地,也可以使用 `bufio` 包中缓冲写入。`bufio` 包中定义了 `type Writer struct{...}` 。
-bufio.Writer 实现了 Write 方法:
+`bufio.Writer` 实现了 `Write()` 方法:
```go
func (b *Writer) Write(p []byte) (nn int, err error)
@@ -64,7 +64,7 @@ func NewWriter(wr io.Writer) (b *Writer)
在缓冲写入的最后千万不要忘了使用 `Flush()`,否则最后的输出不会被写入。
-在 15.2-15.8 章节,我们将使用 `fmt.Fprint` 函数向 `http.ResponseWriter` 写入,其同样实现了 io.Writer 接口。
+在 [15.2](15.2.md)-[15.8](15.8.md) 章节,我们将使用 `fmt.Fprint()` 函数向 `http.ResponseWriter` 写入,其同样实现了 `io.Writer` 接口。
**练习 12.7**:[remove_3till5char.go](exercises/chapter_12/remove_3till5char.go)
diff --git a/eBook/12.9.md b/eBook/12.9.md
index 9d7d2ba8b..0c7dbc21f 100644
--- a/eBook/12.9.md
+++ b/eBook/12.9.md
@@ -8,12 +8,12 @@
下面是一些术语说明:
-- 数据结构 --> 指定格式 = `序列化` 或 `编码`(传输之前)
-- 指定格式 --> 数据结构 = `反序列化` 或 `解码`(传输之后)
+- 数据结构 --> 指定格式 = **序列化** 或 **编码**(传输之前)
+- 指定格式 --> 数据结构 = **反序列化** 或 **解码**(传输之后)
-序列化是在内存中把数据转换成指定格式(data -> string),反之亦然(string -> data)。
+序列化是在内存中把数据转换成指定格式(数据 -> 字符串),反之亦然(字符串 -> 数据)。
-编码也是一样的,只是输出一个数据流(实现了 io.Writer 接口);解码是从一个数据流(实现了 io.Reader)输出到一个数据结构。
+编码也是一样的,只是输出一个数据流(实现了 `io.Writer` 接口);解码是从一个数据流(实现了 `io.Reader`)输出到一个数据结构。
我们都比较熟悉 XML 格式(参阅 [12.10](12.9.md));但有些时候 JSON(JavaScript Object Notation,参阅 [http://json.org](http://json.org))被作为首选,主要是由于其格式上非常简洁。通常 JSON 被用于 web 后端和浏览器之间的通讯,但是在其它场景也同样的有用。
@@ -30,9 +30,9 @@
尽管 XML 被广泛的应用,但是 JSON 更加简洁、轻量(占用更少的内存、磁盘及网络带宽)和更好的可读性,这也使它越来越受欢迎。
-Go 语言的 json 包可以让你在程序中方便的读取和写入 JSON 数据。
+Go 语言的 `json` 包可以让你在程序中方便的读取和写入 JSON 数据。
-我们将在下面的例子里使用 json 包,并使用练习 10.1 [vcard.go](exercises/chapter_10/vcard.go) 中一个简化版本的 Address 和 VCard 结构(为了简单起见,我们忽略了很多错误处理,不过在实际应用中你必须要合理的处理这些错误,参阅 13 章)
+我们将在下面的例子里使用 `json` 包,并使用练习 10.1 [vcard.go](exercises/chapter_10/vcard.go) 中一个简化版本的 `Address` 和 `VCard` 结构(为了简单起见,我们忽略了很多错误处理,不过在实际应用中你必须要合理的处理这些错误,参阅 [13 章](13.0.md))。
示例 12.16 [json.go](examples/chapter_12/json.go):
@@ -79,7 +79,7 @@ func main() {
}
```
-`json.Marshal()` 的函数签名是 `func Marshal(v interface{}) ([]byte, error)`,下面是数据编码后的 JSON 文本(实际上是一个 []byte):
+`json.Marshal()` 的函数签名是 `func Marshal(v interface{}) ([]byte, error)`,下面是数据编码后的 JSON 文本(实际上是一个 `[]byte`):
```javascript
{
@@ -100,50 +100,50 @@ func main() {
出于安全考虑,在 web 应用中最好使用 `json.MarshalforHTML()` 函数,其对数据执行 HTML 转码,所以文本可以被安全地嵌在 HTML `