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 `