This commit is contained in:
Unknwon
2015-03-01 01:07:43 -05:00
parent 64bb8b3ea3
commit 0d75fa5848
8 changed files with 182 additions and 169 deletions

View File

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

View File

@@ -1,47 +1,48 @@
# 8.6 将 map 的键值对调 # 8.6 将 map 的键值对调
194 这里倒置是指调换 key 和 value。如果 map 的值类型可以作为 key 且所有的 value 是唯一的,那么通过下面的方法可以简单的做到键值对调。
这里倒置是指调换key和value。如果map的值类型可以作为key且所有的value是唯一的那么通过下面的方法可以简单的做到倒置 示例 8.7 [invert_map.go](examples/chapter_8/invert_map.go)
示例 8.7 [invert_map.go](examples/chapter_8/invert_map.go) ```go
package main
import (
"fmt"
)
package main var (
import ( barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23,
"fmt" "delta": 87, "echo": 56, "foxtrot": 12,
) "golf": 34, "hotel": 16, "indio": 87,
"juliet": 65, "kili": 43, "lima": 98}
)
var ( func main() {
barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23, invMap := make(map[int]string, len(barVal))
"delta": 87, "echo": 56, "foxtrot": 12, for k, v := range barVal {
"golf": 34, "hotel": 16, "indio": 87, invMap[v] = k
"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()
} }
fmt.Println("inverted:")
for k, v := range invMap {
fmt.Printf("Key: %v, Value: %v / ", k, v)
}
fmt.Println()
}
```
输出结果: 输出结果:
inverted: 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 / 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) - [目录](directory.md)
- 上一节:[map排序](08.5.md) - 上一节:[map排序](08.5.md)
- 下一[](09.0.md) - 下一[](09.0.md)

View File

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

View File

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

View File

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

View File

@@ -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” ```go
import sync
mu sync.Mutex type Info struct {
// ... other fields, e.g.: Str string mu sync.Mutex
} // ... other fields, e.g.: Str string
如果一个函数想要改变这个变量可以这样写: }
```
func Update(info *Info) {
```go
如果一个函数想要改变这个变量可以这样写: 如果一个函数想要改变这个变量可以这样写:
// critical section:
func Update(info *Info) { func Update(info *Info) {
// end critical section info.mu.Lock()
// critical section: // critical section:
info.Str = // new value
// end critical section // end critical section
还有一个很有用的例子是通过Mutex来实现一个可以上锁的共享缓冲器:
info.mu.Unlock() info.mu.Unlock()
lock sync.Mutex }
buffer bytes.Buffer ```

View File

@@ -1,4 +1,6 @@
#精密计算和big包 # 精密计算和 big
202
我们知道有些时候通过编程的方式去进行计算是不精确的。如果你使用Go语言中的fload64类型进行浮点运算返回结果将精确到15位足以满足大多数的任务。当对超出in64或者uint64类型这样的大数进行计算时如果对精度没有要求float32或者float64可以胜任但如果对精度有严格要求的时候我们不能使用浮点数在内存中它们只能被近似的表示。 我们知道有些时候通过编程的方式去进行计算是不精确的。如果你使用Go语言中的fload64类型进行浮点运算返回结果将精确到15位足以满足大多数的任务。当对超出in64或者uint64类型这样的大数进行计算时如果对精度没有要求float32或者float64可以胜任但如果对精度有严格要求的时候我们不能使用浮点数在内存中它们只能被近似的表示。
对于整数的高精度计算Go语言中提供了big包。其中包含了math包有用来表示大整数的big.Int和表示大有理数的big.Rat类型(可以表示为2/5或3.1416这样的分数,而不是无理数或π)。这些类型可以实现任意位类型的数字,只要内存足够大。缺点是更大的内存和处理开销使它们使用起来要比内置的数字类型慢很多。 对于整数的高精度计算Go语言中提供了big包。其中包含了math包有用来表示大整数的big.Int和表示大有理数的big.Rat类型(可以表示为2/5或3.1416这样的分数,而不是无理数或π)。这些类型可以实现任意位类型的数字,只要内存足够大。缺点是更大的内存和处理开销使它们使用起来要比内置的数字类型慢很多。
@@ -7,7 +9,7 @@
示例 9.2 [big.go](examples/chapter_9/big.go) 示例 9.2 [big.go](examples/chapter_9/big.go)
package main package main
import ( import (
"fmt" "fmt"
"math"" "math""

View File

@@ -65,14 +65,18 @@
- 7.4 [切片重组](07.4.md) - 7.4 [切片重组](07.4.md)
- 7.5 [切片的复制与追加](07.5.md) - 7.5 [切片的复制与追加](07.5.md)
- 7.6 [字符串、数组和切片的应用](07.6.md) - 7.6 [字符串、数组和切片的应用](07.6.md)
- 第8章Maps - 第8章[Maps](08.0.md)
- 8.1 [声明、初始化和 make](08.1.md) - 8.1 [声明、初始化和 make](08.1.md)
- 8.2 [测试键值对是否存在及删除元素](08.2.md) - 8.2 [测试键值对是否存在及删除元素](08.2.md)
- 8.3 [for-range 的配套用法](08.3.md) - 8.3 [for-range 的配套用法](08.3.md)
- 8.4 [map 类型的切片](08.4.md) - 8.4 [map 类型的切片](08.4.md)
- 8.5 [map 的排序](08.5.md) - 8.5 [map 的排序](08.5.md)
- 8.6 [将 map 的键值对调](08.6.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 - 第10章结构struct与方法method
- 第11章接口interface与反射reflection - 第11章接口interface与反射reflection