Unknwon 11 ani în urmă
părinte
comite
0d75fa5848
8 a modificat fișierele cu 212 adăugiri și 199 ștergeri
  1. 1 1
      README.md
  2. 34 33
      eBook/08.6.md
  3. 6 4
      eBook/09.0.md
  4. 94 94
      eBook/09.1.md
  5. 44 42
      eBook/09.2.md
  6. 22 20
      eBook/09.3.md
  7. 5 3
      eBook/09.4.md
  8. 6 2
      eBook/directory.md

+ 1 - 1
README.md

@@ -9,7 +9,7 @@
 
 ## 翻译进度
 
-8.5 [map 的排序](eBook/08.5.md)
+9.3 [锁和 sync 包](eBook/09.3.md)
 
 ## 支持本书
 

+ 34 - 33
eBook/08.6.md

@@ -1,47 +1,48 @@
 # 8.6 将 map 的键值对调
 
-194
-
-这里倒置是指调换key和value。如果map的值类型可以作为key且所有的value是唯一的,那么通过下面的方法可以简单的做到倒置:
-
-示例 8.7 [invert_map.go](examples/chapter_8/invert_map.go)
-
-	package main
-	import (
-		"fmt"
-	)
-
-	var (
-		barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23,
-								"delta": 87, "echo": 56, "foxtrot": 12,
-								"golf": 34, "hotel": 16, "indio": 87,
-								"juliet": 65, "kili": 43, "lima": 98}
-	)
-
-	func main() {
-		invMap := make(map[int]string, len(barVal))
-		for k, v := range barVal {
-			invMap[v] = k
-		}
-		fmt.Println("inverted:")
-		for k, v := range invMap {
-			fmt.Printf("Key: %v, Value: %v / ", k, v)
-		}
-		fmt.Println()
+这里倒置是指调换 key 和 value。如果 map 的值类型可以作为 key 且所有的 value 是唯一的,那么通过下面的方法可以简单的做到键值对调。
+
+示例 8.7 [invert_map.go](examples/chapter_8/invert_map.go):
+
+```go
+package main
+import (
+	"fmt"
+)
+
+var (
+	barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23,
+							"delta": 87, "echo": 56, "foxtrot": 12,
+							"golf": 34, "hotel": 16, "indio": 87,
+							"juliet": 65, "kili": 43, "lima": 98}
+)
+
+func main() {
+	invMap := make(map[int]string, len(barVal))
+	for k, v := range barVal {
+		invMap[v] = k
 	}
+	fmt.Println("inverted:")
+	for k, v := range invMap {
+		fmt.Printf("Key: %v, Value: %v / ", k, v)
+	}
+	fmt.Println()
+}
+```
 
 输出结果:
 
 	inverted:
 	Key: 34, Value: golf / Key: 23, Value: charlie / Key: 16, Value: hotel / Key: 87, Value: delta / Key: 98, Value: lima / Key: 12, Value: foxtrot / Key: 43, Value: kili / Key: 56, Value: bravo / Key: 65, Value: juliet /
 
-如果原始value值不唯一那么这么做肯定会出错;为了保证不出错,当遇到不唯一的key时应当立刻停止,这样可能会导致没有包含原map的所有键值对!一种解决方法就是仔细检查唯一性并且使用多值map,比如使用`map[int][]string`类型。
+如果原始 value 值不唯一那么这么做肯定会出错;为了保证不出错,当遇到不唯一的 key 时应当立刻停止,这样可能会导致没有包含原 map 的所有键值对!一种解决方法就是仔细检查唯一性并且使用多值 map,比如使用 `map[int][]string` 类型。
 
-练习 8.2: map_drinks.go
+**练习 8.2**
 
 构造一个将英文饮料名映射为法语(或者任意你的母语)的集合;先打印所有的饮料,然后打印原名和翻译后的名字。接下来按照英文名排序后再打印出来。
 
-##链接
+## 链接
+
 - [目录](directory.md)
-- 上一节:[map排序](08.5.md)
-- 下一:[包](09.0.md)
+- 上一节:[map排序](08.5.md)
+- 下一:[包](09.0.md)

+ 6 - 4
eBook/09.0.md

@@ -1,7 +1,9 @@
-#9.0 包
+# 9.0 包(package)
 
+本章主要针对 Go 语言的包展开讲解。
+
+## 链接
 
-##链接
 - [目录](directory.md)
-- 上一节:[]()
-- 下一节:[标准库概述](09.1.md)
+- 上一章:[将 map 的键值对调](08.6.md)
+- 下一节:[标准库概述](09.1.md)

+ 94 - 94
eBook/09.1.md

@@ -1,95 +1,95 @@
-#A 标准库
-#9.1 标准库概述
-像fmt,os等这样具有常用功能的内置包在Go语言中有150个以上,它们被称为标准库,大部分(一些底层的除外)内置于Go本身。记录在:http://golang.org/pkg/。
-
-在贯穿本书的例子和练习中,我们都是用标准库的包。可以通过查阅p.350包中的内容快速找到相关的包的实例。这里我们只是按功能进行分组来介绍这些包的简单用途,我们不会深入讨论他们的内部结构。
-
-unsafe: 包含了一些打破Go语言“类型安全”的命令,一般的程序中不会被使用,可用在C/C++程序的调用中。
-
-syscall-os-os/exec:  
-os: 提供给我们一个平台无关性的操作系统功能接口,采用类Unix设计,隐藏了不同操作系统间差异,让不同的文件系统和操作系统对象表现一致。  
-os/exec: 提供我们运行外部操作系统命令和程序的方式。  
-syscall: 底层的外部包,提供了操作系统底层调用的基本接口。
-
-通过一个Go程序让Linux重启来体现它的能力(通过sudo ./6.out来执行程序):
-
-示例 9.1 [reboot.go](examples/chapter_9/reboot.go)
-
-	package main
-	import (
-		"syscall"
-	)
-	
-	const LINUX_REBOOT_MAGIC1 uintptr = 0xfee1dead
-	const LINUX_REBOOT_MAGIC2 uintptr = 672274793
-	const LINUX_REBOOT_CMD_RESTART uintptr = 0x1234567
-
-	func main() {
-		syscall.Syscall(syscall.SYS_REBOOT,
-			LINUX_REBOOT_MAGIC1,
-			LINUX_REBOOT_MAGIC2,
-			LINUX_REBOOT_CMD_RESTART)	
-	}
-archive/tar and /zip-compress:压缩(解压缩)文件功能。
-
-fmt-io-bufio-path/filepath-flag:  
-fmt: 提供了格式化输入输出功能。  
-io: 提供了基本输入输出功能,大多数是围绕系统功能的封装。  
-bufio: 缓冲输入输出功能的封装。  
-path/filepath: 用来操作在当前系统中的目标文件名路径。  
-flag: 对命令行参数的操作。  
-
-strings-strconv-unicode-regexp-bytes:  
-strings: 提供对字符串的操作。  
-strconv: 提供将字符串转换为基础类型的功能。   
-unicode: 为unicode型的字符串提供特殊的功能。   
-regexp: 正则表达式功能。  
-bytes: 提供对字符型分片的操作。  
-index/suffixarray: 子字符串快速查询。
-
-math-math/cmath-math/big-math/rand-sort:  
-math: 基本的数学函数。  
-math/cmath: 对负责数字的操作。  
-math/rand: 伪随机数生成。  
-sort: 为数组排序和自定义集合。  
-math/big: 大数的实现和计算。    
-
-container: /list-ring-heap: 实现对集合的操作。  
-list: 双链表。  
-示例,如何遍历一个链表(当l是*List):
-
-	for e := l.Front(); e != nil; e = e.Next() {
-		//do something with e.Value
-	}
-ring: 环形链表。
-
-time-log:  
-time: 日期和时间的基本操作。  
-log: 记录程序运行时产生的日志,我们将在后面的章节使用它。
-
-encoding/json-encoding/xml-text/template:    
-encoding/json: 读取并解码和写入并编码Json数据。  
-encoding/xml:简单的XML1.0解析器,有关Json和XML的实例请查阅12.9/10章节。  
-text/template:生成像HTML一样的数据与文本混合的数据驱动模板(参见15.7章节)。  
-
-net-net/http-html:(参见第15章)   
-net: 网络数据的基本操作。  
-http: 提供了一个可扩展的HTTP服务器和基础客户端,解析HTTP请求和回复。  
-html: HTML5解析器。  
-
-runtime: Go程序运行时的交互操作,例如垃圾回收和协程创建。  
-reflect: 实现通过程序运行时自省,让程序操作任意类型的变量。  
-
-exp包中有许多将被编译为新包的实验性的包。它们将成为独立的包在下次稳定版本发布的时候。如果前一个版本已经存在了,它们将被作为果实的包被回收。然而Go1.0发布的时候并不包含过时或者实验性的包。
-
-练习9.1: dlinked_list.go  
-使用container/list包实现一个双向链表,将101,102,103放入其中并打印出来。 
-
-练习9.2: size_int.go  
-通过使用unsafe包中的方法来测试你电脑上一个整型变量占用多少个字节。
-
-##链接
+# 9.1 标准库概述
+
+像 fmt,os 等这样具有常用功能的内置包在 Go 语言中有 150 个以上,它们被称为标准库,大部分(一些底层的除外)内置于 Go 本身。记录在: http://golang.org/pkg/。
+
+在贯穿本书的例子和练习中,我们都是用标准库的包。可以通过查阅第 350 页包中的内容快速找到相关的包的实例。这里我们只是按功能进行分组来介绍这些包的简单用途,我们不会深入讨论他们的内部结构。
+
+- unsafe: 包含了一些打破 Go 语言“类型安全”的命令,一般的程序中不会被使用,可用在 C/C++ 程序的调用中。
+- syscall-os-os/exec:  
+	- os: 提供给我们一个平台无关性的操作系统功能接口,采用类Unix设计,隐藏了不同操作系统间差异,让不同的文件系统和操作系统对象表现一致。  
+	- os/exec: 提供我们运行外部操作系统命令和程序的方式。  
+	- syscall: 底层的外部包,提供了操作系统底层调用的基本接口。
+
+通过一个Go程序让Linux重启来体现它的能力(通过 `sudo ./6.out` 来执行程序)。
+
+示例 9.1 [reboot.go](examples/chapter_9/reboot.go):
+
+```go
+package main
+import (
+	"syscall"
+)
+
+const LINUX_REBOOT_MAGIC1 uintptr = 0xfee1dead
+const LINUX_REBOOT_MAGIC2 uintptr = 672274793
+const LINUX_REBOOT_CMD_RESTART uintptr = 0x1234567
+
+func main() {
+	syscall.Syscall(syscall.SYS_REBOOT,
+		LINUX_REBOOT_MAGIC1,
+		LINUX_REBOOT_MAGIC2,
+		LINUX_REBOOT_CMD_RESTART)
+}
+```
+
+- archive/tar 和 /zip-compress:压缩(解压缩)文件功能。
+- fmt-io-bufio-path/filepath-flag:  
+	- fmt: 提供了格式化输入输出功能。  
+	- io: 提供了基本输入输出功能,大多数是围绕系统功能的封装。  
+	- bufio: 缓冲输入输出功能的封装。  
+	- path/filepath: 用来操作在当前系统中的目标文件名路径。  
+	- flag: 对命令行参数的操作。  
+- strings-strconv-unicode-regexp-bytes:  
+	- strings: 提供对字符串的操作。  
+	- strconv: 提供将字符串转换为基础类型的功能。
+	- unicode: 为 unicode 型的字符串提供特殊的功能。
+	- regexp: 正则表达式功能。  
+	- bytes: 提供对字符型分片的操作。  
+	- index/suffixarray: 子字符串快速查询。
+- math-math/cmath-math/big-math/rand-sort:  
+	- math: 基本的数学函数。  
+	- math/cmath: 对负责数字的操作。  
+	- math/rand: 伪随机数生成。  
+	- sort: 为数组排序和自定义集合。  
+	- math/big: 大数的实现和计算。    
+- container: /list-ring-heap: 实现对集合的操作。  
+	- list: 双链表。
+
+示例,如何遍历一个链表(当 l 是 `*List`):
+
+```go
+for e := l.Front(); e != nil; e = e.Next() {
+	//do something with e.Value
+}
+```
+
+	- ring: 环形链表。
+
+- time-log:  
+	- time: 日期和时间的基本操作。  
+	- log: 记录程序运行时产生的日志,我们将在后面的章节使用它。
+- encoding/json-encoding/xml-text/template:
+	- encoding/json: 读取并解码和写入并编码 Json 数据。  
+	- encoding/xml:简单的 XML1.0 解析器,有关 Json 和 XML 的实例请查阅第 12.9/10 章节。  
+	- text/template:生成像 HTML 一样的数据与文本混合的数据驱动模板(参见第 15.7 节)。  
+- net-net/http-html:(参见第 15 章)
+	- net: 网络数据的基本操作。  
+	- http: 提供了一个可扩展的 HTTP 服务器和基础客户端,解析 HTTP 请求和回复。  
+	- html: HTML5解析器。  
+- runtime: Go程序运行时的交互操作,例如垃圾回收和协程创建。  
+- reflect: 实现通过程序运行时自省,让程序操作任意类型的变量。  
+
+exp 包中有许多将被编译为新包的实验性的包。它们将成为独立的包在下次稳定版本发布的时候。如果前一个版本已经存在了,它们将被作为果实的包被回收。然而Go1.0发布的时候并不包含过时或者实验性的包。
+
+** 练习9.1 **
+
+使用 container/list 包实现一个双向链表,将 101,102,103 放入其中并打印出来。
+
+**练习9.2 **
+
+通过使用 unsafe 包中的方法来测试你电脑上一个整型变量占用多少个字节。
+
+## 链接
 - [目录](directory.md)
-- 上一节:
-- 下一节:[regexp包](09.2.md)
-
+- 上一节:[包(package)](09.0.md)
+- 下一节:[regexp 包](09.2.md)

+ 44 - 42
eBook/09.2.md

@@ -1,45 +1,47 @@
-#9.2 regexp包
-正则表达式语法和使用的详细信息请参考http://en.wikipedia.org/wiki/Regular_expression
-
-在下面的程序里,我们将在字符串中对正则表达式进行匹配
-
-如果是简单模式,使用Match方法便可: ok, _ := regexp.Match(pat, []byte(searchIn))  
-变量ok将返回true或者false,我们也可以使用MatchString: ok, _ := regexp.MathString(pat, searchIn)
-
-更多方法中,必须先将正则通过Compile方法返回一个Regexp对象。然后我们将掌握一些匹配,查找,替换相关的功能。
-
-示例 9.2 [pattern.go](examples/chapter_9/pattern.go)
-	
-	package main
-	import (
-    	"fmt"
-    	"regexp"
-    	"strconv"
-	)
-	func main() {
-    	//目标字符串
-    	searchIn := "John: 2578.34 William: 4567.23 Steve: 5632.18"
-    	pat := "[0-9]+.[0-9]+" //正则
-
-    	f := func(s string) string{
-        	v, _ := strconv.ParseFloat(s, 32)
-        	return strconv.FormatFloat(v * 2, 'f', 2, 32)
-    	}
-
-    	if ok, _ := regexp.Match(pat, []byte(searchIn)); ok {
-        fmt.Println("Match Found!")
-    	}
-
-    	re, _ := regexp.Compile(pat)
-    	//将匹配到的部分替换为"##.#"
-    	str := re.ReplaceAllString(searchIn, "##.#")
-    	fmt.Println(str)
-    	//参数为函数时
-    	str2 := re.ReplaceAllStringFunc(searchIn, f)
-    	fmt.Println(str2)
+# 9.2 regexp 包
+
+正则表达式语法和使用的详细信息请参考 http://en.wikipedia.org/wiki/Regular_expression
+
+在下面的程序里,我们将在字符串中对正则表达式进行匹配。
+
+如果是简单模式,使用 Match 方法便可:`ok, _ := regexp.Match(pat, []byte(searchIn))`
+
+变量 ok 将返回 true 或者 false,我们也可以使用 MatchString:`ok, _ := regexp.MathString(pat, searchIn)`
+
+更多方法中,必须先将正则通过 Compile 方法返回一个 Regexp 对象。然后我们将掌握一些匹配,查找,替换相关的功能。
+
+示例 9.2 [pattern.go](examples/chapter_9/pattern.go):
+
+```go
+package main
+import (
+	"fmt"
+	"regexp"
+	"strconv"
+)
+func main() {
+	//目标字符串
+	searchIn := "John: 2578.34 William: 4567.23 Steve: 5632.18"
+	pat := "[0-9]+.[0-9]+" //正则
+
+	f := func(s string) string{
+    	v, _ := strconv.ParseFloat(s, 32)
+    	return strconv.FormatFloat(v * 2, 'f', 2, 32)
 	}
 
+	if ok, _ := regexp.Match(pat, []byte(searchIn)); ok {
+    fmt.Println("Match Found!")
+	}
 
+	re, _ := regexp.Compile(pat)
+	//将匹配到的部分替换为"##.#"
+	str := re.ReplaceAllString(searchIn, "##.#")
+	fmt.Println(str)
+	//参数为函数时
+	str2 := re.ReplaceAllStringFunc(searchIn, f)
+	fmt.Println(str2)
+}
+```
 
 输出结果:
 
@@ -47,10 +49,10 @@
 	John: ##.# William: ##.# Steve: ##.#
 	John: 5156.68 William: 9134.46 Steve: 11264.36
 
-Compile函数也可能返回一个错误,我们在使用时忽略对错误的判断是因为我们确信自己正则表达式是有效的。当用户输入或从数据中获取正则表达式的时候,我们有必要去检验它的正确性。另外我们也可以使用MustCompile方法,它可以像Compile方法一样检验正则的有效性,但是当正则不合法时程序将panic(详情查看13.2章节)。
+Compile 函数也可能返回一个错误,我们在使用时忽略对错误的判断是因为我们确信自己正则表达式是有效的。当用户输入或从数据中获取正则表达式的时候,我们有必要去检验它的正确性。另外我们也可以使用 MustCompile 方法,它可以像 Compile 方法一样检验正则的有效性,但是当正则不合法时程序将 panic(详情查看第 13.2 节)。
 
+## 链接
 
-##链接
 - [目录](directory.md)
 - 上一节:[标准库概述](09.1.md)
-- 下一节:[锁和sync包](09.2.md)
+- 下一节:[锁和 sync 包](09.3.md)

+ 22 - 20
eBook/09.3.md

@@ -1,32 +1,34 @@
-#9.3锁和sync包
-在一些复杂的程序中,通常通过不同线程执行不同应用来实现程序的并发。当不同线程要使用同一个变量时,经常会出现一个问题:无法预知变量被不同线程修改的顺序!(这通常被称为资源竞争,指不同线程对同一变量使用的竞争。)显然这无法让人容忍,那我们该如何解决这个问题呢?
+# 9.3 锁和 sync 包
+
+在一些复杂的程序中,通常通过不同线程执行不同应用来实现程序的并发。当不同线程要使用同一个变量时,经常会出现一个问题:无法预知变量被不同线程修改的顺序!(这通常被称为资源竞争,指不同线程对同一变量使用的竞争)显然这无法让人容忍,那我们该如何解决这个问题呢?
 
 经典的做法是一次只能让一个线程对共享变量进行操作。当变量被一个线程改变时(临界区),我们为它上锁,直到这个线程执行完成并解锁后,其他线程才能访问它。
 
-特别是我们之前章节学习的map类型是不存在锁的机制来实现这种效果(出于对性能的考虑),所以map类型是非线程安全的.当并行访问一个共享的map类型的数据,map数据将会出错。
+特别是我们之前章节学习的 map 类型是不存在锁的机制来实现这种效果(出于对性能的考虑),所以 map 类型是非线程安全的.当并行访问一个共享的 map 类型的数据,map 数据将会出错。
+
+在 Go 语言中这种锁的机制是通过 sync 包中 Mutex 来实现的。sync 来源于 "synchronized" 一词,这意味着线程将有序的对同一变量进行访问。
 
-在Go语言中这种锁的机制是通过sync包中Mutex来实现的。sync来源于"synchronized"一词,这意味着线程将有序的对同一变量进行访问。
+sync.Mutex 是一个互斥锁,它的作用是守护在临界区入口来确保同一时间只能有一个线程进入临界区
 
-sync.Mutex是一个互斥锁,它的作用是守护在临界区入口来确保同一时间只能有一个线程进入临界区。
+假设 info 是一个需要上锁的放在共享内存中的变量。通过包含 Mutex 来实现的一个典型例子如下:
 
-假设info是一个需要上锁的放在共享内存中的变量。通过包含Mutex来实现的一个典型例子如下:
-	
-	 import  “sync”
      	type Info struct {
		mu sync.Mutex
		// ... other fields, e.g.: Str string
	}
如果一个函数想要改变这个变量可以这样写:
-	
-	func Update(info *Info) {
-		info.mu.Lock()
        // critical section:
        info.Str = // new value
        // end critical section
        info.mu.Unlock()
	}
还有一个很有用的例子是通过Mutex来实现一个可以上锁的共享缓冲器:
-
	type SyncedBuffer struct {
-		lock 	sync.Mutex
-		buffer  bytes.Buffer
-	}
+```go
+import  “sync”

type Info struct {
	mu sync.Mutex
	// ... other fields, e.g.: Str string
}
```

```go
如果一个函数想要改变这个变量可以这样写:
 
-在sync包中还有一个RWMutex锁:他能通过RLock()来允许同一时间多个线程对变量进行读操作,但是只能一个线程进行写操作。如果使用Lock()将和普通的Mutex作用相同。包中还有一个方便的Once类型变量的方法once.Do(call),这个方法确保被调用函数只能被调用一次。
+func Update(info *Info) {
+	info.mu.Lock()
    // critical section:
    info.Str = // new value
    // end critical section
    info.mu.Unlock()
}
```

还有一个很有用的例子是通过 Mutex 来实现一个可以上锁的共享缓冲器:
+
```go
type SyncedBuffer struct {
+	lock 	sync.Mutex
+	buffer  bytes.Buffer
+}
+```
 
-相对简单的情况下,通过使用sync包可以解决同一时间只能一个线程访问变量或map类型数据的问题。如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过goroutines和channels来解决问题,这是在Go语言中所提倡用来实现并发的技术。我们将在第14章对其深入了解,并在14.7的章节中对这两种方式进行比较。
+在 sync 包中还有一个 RWMutex 锁:他能通过 RLock() 来允许同一时间多个线程对变量进行读操作,但是只能一个线程进行写操作。如果使用 Lock() 将和普通的 Mutex 作用相同。包中还有一个方便的 Once 类型变量的方法 once.Do(call),这个方法确保被调用函数只能被调用一次
 
+相对简单的情况下,通过使用 sync 包可以解决同一时间只能一个线程访问变量或 map 类型数据的问题。如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过 goroutines 和 channels 来解决问题,这是在 Go 语言中所提倡用来实现并发的技术。我们将在第 14 章对其深入了解,并在第 14.7 节中对这两种方式进行比较。
 
+## 链接
 
-##链接
 - [目录](directory.md)
-- 上一节:[regexp包](09.2.md)
-- 下一节:[精密计算和big包](09.3.md)
+- 上一节:[regexp 包](09.2.md)
+- 下一节:[精密计算和 big 包](09.4.md)

+ 5 - 3
eBook/09.4.md

@@ -1,4 +1,6 @@
-#精密计算和big包
+# 精密计算和 big 包
+
+202
 我们知道有些时候通过编程的方式去进行计算是不精确的。如果你使用Go语言中的fload64类型进行浮点运算,返回结果将精确到15位,足以满足大多数的任务。当对超出in64或者uint64类型这样的大数进行计算时,如果对精度没有要求,float32或者float64可以胜任,但如果对精度有严格要求的时候,我们不能使用浮点数,在内存中它们只能被近似的表示。
 
 对于整数的高精度计算Go语言中提供了big包。其中包含了math包:有用来表示大整数的big.Int和表示大有理数的big.Rat类型(可以表示为2/5或3.1416这样的分数,而不是无理数或π)。这些类型可以实现任意位类型的数字,只要内存足够大。缺点是更大的内存和处理开销使它们使用起来要比内置的数字类型慢很多。
@@ -6,8 +8,8 @@
 大的整型数字是通过big.NewInt(n)来构造的,其中n位int64类型整数。而大有理数是用过big.NewRat(N,D)方法构造.N(分子)和D(分母)都是int64型整数。因为Go语言不支持运算符重载,所以所有大数字类型都有像是Add()和Mul()这样的方法。它们作用于作为receiver的整数和有理数,大多数情况下它们修改receiver并以receiver作为返回结果。因为没有必要创建big.Int类型的临时变量来存放中间结果,所以这样的运算可通过内存链式存储。
 
 示例 9.2 [big.go](examples/chapter_9/big.go)
-	
-	package main
    import (
    	"fmt"
		"math""
		"math/big" 
	)
    func main() {
    	// Here are some calculations with bigInts:
        im := big.NewInt(math.MaxInt64)
        in := im
        io := big.NewInt(1956)
        ip := big.NewInt(1)
        ip.Mul(im, in).Add(ip, im).Div(ip, io)
        fmt.Printf(“Big Int: %v\n”, ip)
        // Here are some calculations with bigInts:
        rm := big.NewRat(math.MaxInt64, 1956)
        rn := big.NewRat(-1956, math.MaxInt64)
        ro := big.NewRat(19, 56)
        rp := big.NewRat(1111, 2222)
        rq := big.NewRat(1, 1)
        rq.Mul(rm, rn).Add(rq, ro).Mul(rq, rp)
        fmt.Printf(“Big Rat: %v\n”, rq)
      }
+
+	package main
    import (
    	"fmt"
		"math""
		"math/big"
	)
    func main() {
    	// Here are some calculations with bigInts:
        im := big.NewInt(math.MaxInt64)
        in := im
        io := big.NewInt(1956)
        ip := big.NewInt(1)
        ip.Mul(im, in).Add(ip, im).Div(ip, io)
        fmt.Printf(“Big Int: %v\n”, ip)
        // Here are some calculations with bigInts:
        rm := big.NewRat(math.MaxInt64, 1956)
        rn := big.NewRat(-1956, math.MaxInt64)
        ro := big.NewRat(19, 56)
        rp := big.NewRat(1111, 2222)
        rq := big.NewRat(1, 1)
        rq.Mul(rm, rn).Add(rq, ro).Mul(rq, rp)
        fmt.Printf(“Big Rat: %v\n”, rq)
      }
 
输出结果:
 
 	Big Int: 43492122561469640008497075573153004
    Big Rat: -37/112

+ 6 - 2
eBook/directory.md

@@ -65,14 +65,18 @@
 	- 7.4 [切片重组](07.4.md)
 	- 7.5 [切片的复制与追加](07.5.md)
 	- 7.6 [字符串、数组和切片的应用](07.6.md)
-- 第8章:Maps
+- 第8章:[Maps](08.0.md)
 	- 8.1 [声明、初始化和 make](08.1.md)
 	- 8.2 [测试键值对是否存在及删除元素](08.2.md)
 	- 8.3 [for-range 的配套用法](08.3.md)
 	- 8.4 [map 类型的切片](08.4.md)
 	- 8.5 [map 的排序](08.5.md)
 	- 8.6 [将 map 的键值对调](08.6.md)
-- 第9章:包(package)
+- 第9章:[包(package)](09.0.md)
+	- 9.1 [标准库概述](09.1.md)
+	- 9.2 [regexp 包](09.2.md)
+	- 9.3 [锁和 sync 包](09.3.md)
+	- 9.4 [精密计算和 big 包](09.4.md)
 - 第10章:结构(struct)与方法(method)
 - 第11章:接口(interface)与反射(reflection)