Merge branch 'master' of github.com:gopl-zh/gopl-zh.github.com

This commit is contained in:
Xargin 2017-03-15 15:18:45 +08:00
commit 25d798e636
7 changed files with 15 additions and 9 deletions

View File

@ -16,7 +16,6 @@ Go语言圣经 [《The Go Programming Language》](http://gopl.io) 中文版本
- http://shifei.me/gopl-zh/ - http://shifei.me/gopl-zh/
- http://2goo.info/media/html/gopl-zh-gh-pages/ - http://2goo.info/media/html/gopl-zh-gh-pages/
- http://docs.plhwin.com/gopl-zh/ - http://docs.plhwin.com/gopl-zh/
- http://gopl-zh.simple-is-best.tk/
- https://docs.hacknode.org/gopl-zh/ - https://docs.hacknode.org/gopl-zh/
**注意,在线预览不是最新版,最新以仓库里的内容为准** **注意,在线预览不是最新版,最新以仓库里的内容为准**

View File

@ -57,7 +57,7 @@ func (path Path) Distance() float64 {
} }
``` ```
Path是一个命名的slice类型而不是Point那样的struct类型然而我们依然可以为它定义方法。在能够给任意类型定义方法这一点上Go和很多其它的面向对象的语言不太一样。因此在Go语言里我们为一些简单的数值、字符串、slice、map来定义一些附加行为很方便。方法可以被声明到任意类型,只要不是一个指针或者一个interface。 Path是一个命名的slice类型而不是Point那样的struct类型然而我们依然可以为它定义方法。在能够给任意类型定义方法这一点上Go和很多其它的面向对象的语言不太一样。因此在Go语言里我们为一些简单的数值、字符串、slice、map来定义一些附加行为很方便。我们可以给同一个包内的任意命名类型定义方法,只要这个命名类型的底层类型(译注:这个例子里,底层类型是指[]Point这个slicePath就是命名类型)不是指针或者interface。
两个Distance方法有不同的类型。他们两个方法之间没有任何关系尽管Path的Distance方法会在内部调用Point.Distance方法来计算每个连接邻接点的线段的长度。 两个Distance方法有不同的类型。他们两个方法之间没有任何关系尽管Path的Distance方法会在内部调用Point.Distance方法来计算每个连接邻接点的线段的长度。

View File

@ -96,7 +96,7 @@ fmt.Println(x) // "{[4398046511618 0 65536]}"
在第一个Println中我们打印一个`*IntSet`的指针这个类型的指针确实有自定义的String方法。第二Println我们直接调用了x变量的String()方法这种情况下编译器会隐式地在x前插入&操作符这样相当远我们还是调用的IntSet指针的String方法。在第三个Println中因为IntSet类型没有String方法所以Println方法会直接以原始的方式理解并打印。所以在这种情况下&符号是不能忘的。在我们这种场景下你把String方法绑定到IntSet对象上而不是IntSet指针上可能会更合适一些不过这也需要具体问题具体分析。 在第一个Println中我们打印一个`*IntSet`的指针这个类型的指针确实有自定义的String方法。第二Println我们直接调用了x变量的String()方法这种情况下编译器会隐式地在x前插入&操作符这样相当远我们还是调用的IntSet指针的String方法。在第三个Println中因为IntSet类型没有String方法所以Println方法会直接以原始的方式理解并打印。所以在这种情况下&符号是不能忘的。在我们这种场景下你把String方法绑定到IntSet对象上而不是IntSet指针上可能会更合适一些不过这也需要具体问题具体分析。
练习6.1: 为bit数组实现下面这些方法 **练习6.1:** 为bit数组实现下面这些方法
```go ```go
func (*IntSet) Len() int // return the number of elements func (*IntSet) Len() int // return the number of elements
@ -105,9 +105,10 @@ func (*IntSet) Clear() // remove all elements from the set
func (*IntSet) Copy() *IntSet // return a copy of the set func (*IntSet) Copy() *IntSet // return a copy of the set
``` ```
**练习 6.2** 定义一个变参方法(*IntSet).AddAll(...int),这个方法可以为一组IntSet值求和比如s.AddAll(1,2,3)。 **练习 6.2** 定义一个变参方法(*IntSet).AddAll(...int),这个方法可以添加一组IntSet比如s.AddAll(1,2,3)。
**练习 6.3** (*IntSet).UnionWith会用|操作符计算两个集合的交集我们再为IntSet实现另外的几个函数IntersectWith(交集元素在A集合B集合均出现),DifferenceWith(差集元素出现在A集合未出现在B集合),SymmetricDifference(并差集元素出现在A但没有出现在B或者出现在B没有出现在A)。 **练习 6.3** (*IntSet).UnionWith会用|操作符计算两个集合的交集我们再为IntSet实现另外的几个函数IntersectWith(交集元素在A集合B集合均出现),DifferenceWith(差集元素出现在A集合未出现在B集合),SymmetricDifference(并差集元素出现在A但没有出现在B或者出现在B没有出现在A)。
练习6.4: 实现一个Elems方法返回集合中的所有元素用于做一些range之类的遍历操作。
***练习6.4: ** 实现一个Elems方法返回集合中的所有元素用于做一些range之类的遍历操作。
**练习 6.5** 我们这章定义的IntSet里的每个字都是用的uint64类型但是64位的数值可能在32位的平台上不高效。修改程序使其使用uint类型这种类型对于32位平台来说更合适。当然了这里我们可以不用简单粗暴地除64可以定义一个常量来决定是用32还是64这里你可能会用到平台的自动判断的一个智能表达式32 << (^uint(0) >> 63) **练习 6.5** 我们这章定义的IntSet里的每个字都是用的uint64类型但是64位的数值可能在32位的平台上不高效。修改程序使其使用uint类型这种类型对于32位平台来说更合适。当然了这里我们可以不用简单粗暴地除64可以定义一个常量来决定是用32还是64这里你可能会用到平台的自动判断的一个智能表达式32 << (^uint(0) >> 63)

View File

@ -108,7 +108,13 @@ html body div div h2: B Definitions for Character Normalization
... ...
``` ```
**练习 7.17** 扩展xmlselect程序以便让元素不仅仅可以通过名称选择也可以通过它们CSS样式上属性进行选择例如一个像这样<div id="page" class="wide">的元素可以通过匹配id或者class同时还有它的名称来进行选择。 **练习 7.17** 扩展xmlselect程序以便让元素不仅仅可以通过名称选择也可以通过它们CSS样式上属性进行选择例如一个像这样
``` html
<div id="page" class="wide">
```
的元素可以通过匹配id或者class同时还有它的名称来进行选择。
**练习 7.18** 使用基于标记的解码API编写一个可以读取任意XML文档和构造这个文档所代表的普通节点树的程序。节点有两种类型CharData节点表示文本字符串和 Element节点表示被命名的元素和它们的属性。每一个元素节点有一个字节点的切片。 **练习 7.18** 使用基于标记的解码API编写一个可以读取任意XML文档和构造这个文档所代表的普通节点树的程序。节点有两种类型CharData节点表示文本字符串和 Element节点表示被命名的元素和它们的属性。每一个元素节点有一个字节点的切片。

View File

@ -4,4 +4,4 @@
相反一个goroutine会以一个很小的栈开始其生命周期一般只需要2KB。一个goroutine的栈和操作系统线程一样会保存其活跃或挂起的函数调用的本地变量但是和OS线程不太一样的是一个goroutine的栈大小并不是固定的栈的大小会根据需要动态地伸缩。而goroutine的栈的最大值有1GB比传统的固定大小的线程栈要大得多尽管一般情况下大多goroutine都不需要这么大的栈。 相反一个goroutine会以一个很小的栈开始其生命周期一般只需要2KB。一个goroutine的栈和操作系统线程一样会保存其活跃或挂起的函数调用的本地变量但是和OS线程不太一样的是一个goroutine的栈大小并不是固定的栈的大小会根据需要动态地伸缩。而goroutine的栈的最大值有1GB比传统的固定大小的线程栈要大得多尽管一般情况下大多goroutine都不需要这么大的栈。
练习 9.4: 创建一个流水线程序支持用channel连接任意数量的goroutine在跑爆内存之前可以创建多少流水线阶段一个变量通过整个流水线需要用多久(这个练习题翻译不是很确定。。) ** 练习 9.4:** 创建一个流水线程序支持用channel连接任意数量的goroutine在跑爆内存之前可以创建多少流水线阶段一个变量通过整个流水线需要用多久(这个练习题翻译不是很确定。。)

View File

@ -6,4 +6,4 @@ Go的运行时包含了其自己的调度器这个调度器使用了一些技
和操作系统的线程调度不同的是Go调度器并不是用一个硬件定时器而是被Go语言"建筑"本身进行调度的。例如当一个goroutine调用了time.Sleep或者被channel调用或者mutex操作阻塞时调度器会使其进入休眠并开始执行另一个goroutine直到时机到了再去唤醒第一个goroutine。因为这种调度方式不需要进入内核的上下文所以重新调度一个goroutine比调度一个线程代价要低得多。 和操作系统的线程调度不同的是Go调度器并不是用一个硬件定时器而是被Go语言"建筑"本身进行调度的。例如当一个goroutine调用了time.Sleep或者被channel调用或者mutex操作阻塞时调度器会使其进入休眠并开始执行另一个goroutine直到时机到了再去唤醒第一个goroutine。因为这种调度方式不需要进入内核的上下文所以重新调度一个goroutine比调度一个线程代价要低得多。
练习 9.5: 写一个有两个goroutine的程序两个goroutine会向两个无buffer channel反复地发送ping-pong消息。这样的程序每秒可以支持多少次通信 ** 练习 9.5: ** 写一个有两个goroutine的程序两个goroutine会向两个无buffer channel反复地发送ping-pong消息。这样的程序每秒可以支持多少次通信

View File

@ -20,4 +20,4 @@ $ GOMAXPROCS=2 go run hacker-cliché.go
在第一次执行时最多同时只能有一个goroutine被执行。初始情况下只有main goroutine被执行所以会打印很多1。过了一段时间后GO调度器会将其置为休眠并唤醒另一个goroutine这时候就开始打印很多0了在打印的时候goroutine是被调度到操作系统线程上的。在第二次执行时我们使用了两个操作系统线程所以两个goroutine可以一起被执行以同样的频率交替打印0和1。我们必须强调的是goroutine的调度是受很多因子影响的而runtime也是在不断地发展演进的所以这里的你实际得到的结果可能会因为版本的不同而与我们运行的结果有所不同。 在第一次执行时最多同时只能有一个goroutine被执行。初始情况下只有main goroutine被执行所以会打印很多1。过了一段时间后GO调度器会将其置为休眠并唤醒另一个goroutine这时候就开始打印很多0了在打印的时候goroutine是被调度到操作系统线程上的。在第二次执行时我们使用了两个操作系统线程所以两个goroutine可以一起被执行以同样的频率交替打印0和1。我们必须强调的是goroutine的调度是受很多因子影响的而runtime也是在不断地发展演进的所以这里的你实际得到的结果可能会因为版本的不同而与我们运行的结果有所不同。
练习9.6: 测试一下计算密集型的并发程序(练习8.5那样的)会被GOMAXPROCS怎样影响到。在你的电脑上最佳的值是多少你的电脑CPU有多少个核心 ** 练习9.6:** 测试一下计算密集型的并发程序(练习8.5那样的)会被GOMAXPROCS怎样影响到。在你的电脑上最佳的值是多少你的电脑CPU有多少个核心