mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 16:15:55 +08:00
fix: fix a lot of incorrect links (#849)
This commit is contained in:
@@ -26,7 +26,7 @@ func main() {
|
|||||||
|
|
||||||
在 Go 的安装文件里包含了一些可以直接使用的包,即标准库。在 Windows 下,标准库的位置在 Go 根目录下的子目录 `pkg\windows_386` 中;在 Linux 下,标准库在 Go 根目录下的子目录 `pkg\linux_amd64` 中(如果是安装的是 32 位,则在 `linux_386` 目录中)。一般情况下,标准包会存放在 `$GOROOT/pkg/$GOOS_$GOARCH/` 目录下。
|
在 Go 的安装文件里包含了一些可以直接使用的包,即标准库。在 Windows 下,标准库的位置在 Go 根目录下的子目录 `pkg\windows_386` 中;在 Linux 下,标准库在 Go 根目录下的子目录 `pkg\linux_amd64` 中(如果是安装的是 32 位,则在 `linux_386` 目录中)。一般情况下,标准包会存放在 `$GOROOT/pkg/$GOOS_$GOARCH/` 目录下。
|
||||||
|
|
||||||
Go 的标准库包含了大量的包(如:`fmt` 和 `os`),但是你也可以创建自己的包([第 9 章](.\09.0.md))。
|
Go 的标准库包含了大量的包(如:`fmt` 和 `os`),但是你也可以创建自己的包([第 9 章](./09.0.md))。
|
||||||
|
|
||||||
如果想要构建一个程序,则包和包内的文件都必须以正确的顺序进行编译。包的依赖关系决定了其构建顺序。
|
如果想要构建一个程序,则包和包内的文件都必须以正确的顺序进行编译。包的依赖关系决定了其构建顺序。
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
现在,数字 `0`、`1` 和 `2` 分别代表未知性别、女性和男性。这些枚举值可以用于测试某个变量或常量的实际值,比如使用 switch/case 结构([第 5.3 节](.\05.3.md))。
|
现在,数字 `0`、`1` 和 `2` 分别代表未知性别、女性和男性。这些枚举值可以用于测试某个变量或常量的实际值,比如使用 switch/case 结构([第 5.3 节](./05.3.md))。
|
||||||
|
|
||||||
在这个例子中,`iota` 可以被用作枚举值:
|
在这个例子中,`iota` 可以被用作枚举值:
|
||||||
|
|
||||||
|
@@ -136,7 +136,7 @@ func main() {
|
|||||||
|
|
||||||
如果你在 Windows 下运行这段代码,则会输出 `The operating system is: windows` 以及相应的环境变量的值;如果你在 Linux 下运行这段代码,则会输出 `The operating system is: linux` 以及相应的的环境变量的值。
|
如果你在 Windows 下运行这段代码,则会输出 `The operating system is: windows` 以及相应的环境变量的值;如果你在 Linux 下运行这段代码,则会输出 `The operating system is: linux` 以及相应的的环境变量的值。
|
||||||
|
|
||||||
这里用到了 `Printf` 的格式化输出的功能([第 4.4.3 节](.\04.4.md))。
|
这里用到了 `Printf` 的格式化输出的功能([第 4.4.3 节](./04.4.md))。
|
||||||
|
|
||||||
## 4.4.2 值类型和引用类型
|
## 4.4.2 值类型和引用类型
|
||||||
|
|
||||||
@@ -146,13 +146,13 @@ func main() {
|
|||||||
|
|
||||||
<img src="images/4.4.2_fig4.1.jpg?raw=true" style="zoom:67%;" />
|
<img src="images/4.4.2_fig4.1.jpg?raw=true" style="zoom:67%;" />
|
||||||
|
|
||||||
另外,像数组([第 7 章](.\07.0.md))和结构([第 10 章](.\10.0md))这些复合类型也是值类型。
|
另外,像数组([第 7 章](./07.0.md))和结构([第 10 章](./10.0md))这些复合类型也是值类型。
|
||||||
|
|
||||||
当使用等号 `=` 将一个变量的值赋值给另一个变量时,如:`j = i`,实际上是在内存中将 `i` 的值进行了拷贝:
|
当使用等号 `=` 将一个变量的值赋值给另一个变量时,如:`j = i`,实际上是在内存中将 `i` 的值进行了拷贝:
|
||||||
|
|
||||||
<img src="images/4.4.2_fig4.2.jpg?raw=true" style="zoom: 67%;" />
|
<img src="images/4.4.2_fig4.2.jpg?raw=true" style="zoom: 67%;" />
|
||||||
|
|
||||||
你可以通过 `&i` 来获取变量 `i` 的内存地址([第 4.9 节](.\04.9.md)),例如:`0xf840000040`(每次的地址都可能不一样)。值类型的变量的值存储在栈中。
|
你可以通过 `&i` 来获取变量 `i` 的内存地址([第 4.9 节](./04.9.md)),例如:`0xf840000040`(每次的地址都可能不一样)。值类型的变量的值存储在栈中。
|
||||||
|
|
||||||
内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。
|
内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ func main() {
|
|||||||
|
|
||||||
<img src="images/4.4.2_fig4.3.jpg?raw=true" style="zoom:67%;" />
|
<img src="images/4.4.2_fig4.3.jpg?raw=true" style="zoom:67%;" />
|
||||||
|
|
||||||
这个内存地址被称之为指针(你可以从上图中很清晰地看到,[第 4.9 节](.\04.9.md) 将会详细说明),这个指针实际上也被存在另外的某一个字中。
|
这个内存地址被称之为指针(你可以从上图中很清晰地看到,[第 4.9 节](./04.9.md) 将会详细说明),这个指针实际上也被存在另外的某一个字中。
|
||||||
|
|
||||||
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
|
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ func main() {
|
|||||||
|
|
||||||
如果 `r1` 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,`r2` 也会受到影响。
|
如果 `r1` 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,`r2` 也会受到影响。
|
||||||
|
|
||||||
在 Go 语言中,指针([第 4.9 节](.\04.9.md))属于引用类型,其它的引用类型还包括 slices([第 7 章](07.0.md)),maps([第 8 章](08.0.md))和 channel([第 13 章](13.0.md))。被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。
|
在 Go 语言中,指针([第 4.9 节](./04.9.md))属于引用类型,其它的引用类型还包括 slices([第 7 章](07.0.md)),maps([第 8 章](08.0.md))和 channel([第 13 章](13.0.md))。被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。
|
||||||
|
|
||||||
## 4.4.3 打印
|
## 4.4.3 打印
|
||||||
|
|
||||||
|
@@ -217,7 +217,7 @@ func IntFromFloat64(x float64) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
不过如果你实际存的数字超出你要转换到的类型的取值范围的话,则会引发 `panic`([第 13.2 节](.\13.2.md))。
|
不过如果你实际存的数字超出你要转换到的类型的取值范围的话,则会引发 `panic`([第 13.2 节](./13.2.md))。
|
||||||
|
|
||||||
**问题 4.1** `int` 和 `int64` 是相同的类型吗?
|
**问题 4.1** `int` 和 `int64` 是相同的类型吗?
|
||||||
|
|
||||||
@@ -468,7 +468,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
实际上,类型别名得到的新类型并非和原类型完全相同,新类型不会拥有原类型所附带的方法([第 10 章](.\10.0.md));`TZ` 可以自定义一个方法用来输出更加人性化的时区信息。
|
实际上,类型别名得到的新类型并非和原类型完全相同,新类型不会拥有原类型所附带的方法([第 10 章](./10.0.md));`TZ` 可以自定义一个方法用来输出更加人性化的时区信息。
|
||||||
|
|
||||||
**练习 4.5** 定义一个 `string` 的类型别名 `Rope`,并声明一个该类型的变量。
|
**练习 4.5** 定义一个 `string` 的类型别名 `Rope`,并声明一个该类型的变量。
|
||||||
|
|
||||||
@@ -511,7 +511,7 @@ fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point
|
|||||||
41 - 3B2 - 101234
|
41 - 3B2 - 101234
|
||||||
U+0041 - U+03B2 - U+101234
|
U+0041 - U+03B2 - U+101234
|
||||||
|
|
||||||
格式化说明符 `%c` 用于表示字符;当和字符配合使用时,`%v` 或 `%d` 会输出用于表示该字符的整数;`%U` 输出格式为 `U+hhhh` 的字符串(另一个示例见[第 5.4.4 节](.\05.4.md))。
|
格式化说明符 `%c` 用于表示字符;当和字符配合使用时,`%v` 或 `%d` 会输出用于表示该字符的整数;`%U` 输出格式为 `U+hhhh` 的字符串(另一个示例见[第 5.4.4 节](./05.4.md))。
|
||||||
|
|
||||||
包 `unicode` 包含了一些针对测试字符的非常有用的函数(其中 `ch` 代表字符):
|
包 `unicode` 包含了一些针对测试字符的非常有用的函数(其中 `ch` 代表字符):
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ fmt.Println(s) //输出 “hello, world!”
|
|||||||
|
|
||||||
在循环中使用加号 `+` 拼接字符串并不是最高效的做法,更好的办法是使用函数 `strings.Join()`([第 4.7.10 节](04.7.md)),有没有更好的办法了?有!使用字节缓冲(`bytes.Buffer`)拼接更加给力([第 7.2.6 节](07.2.md))!
|
在循环中使用加号 `+` 拼接字符串并不是最高效的做法,更好的办法是使用函数 `strings.Join()`([第 4.7.10 节](04.7.md)),有没有更好的办法了?有!使用字节缓冲(`bytes.Buffer`)拼接更加给力([第 7.2.6 节](07.2.md))!
|
||||||
|
|
||||||
在[第 7 章](07.0.md),我们会讲到通过将字符串看作是字节 (`byte`) 的切片 (slice) 来实现对其标准索引法的操作。会在[第 5.4.1 节](05.4.md) 中讲到的 `for` 循环只会根据索引返回字符串中的纯字节,而在[第 5.4.4 节](.\05.4.md)(以及[第 7.6.1 节](07.6.md) 的示例)将会展示如何使用 for-range 循环来实现对 Unicode 字符串的迭代操作。在下一节,我们会学习到许多有关字符串操作的函数和方法,同时 `fmt` 包中的 `fmt.Sprint(x)` 也可以格式化生成并返回你所需要的字符串([第 4.4.3 节](04.3.md))。
|
在[第 7 章](07.0.md),我们会讲到通过将字符串看作是字节 (`byte`) 的切片 (slice) 来实现对其标准索引法的操作。会在[第 5.4.1 节](05.4.md) 中讲到的 `for` 循环只会根据索引返回字符串中的纯字节,而在[第 5.4.4 节](./05.4.md)(以及[第 7.6.1 节](07.6.md) 的示例)将会展示如何使用 for-range 循环来实现对 Unicode 字符串的迭代操作。在下一节,我们会学习到许多有关字符串操作的函数和方法,同时 `fmt` 包中的 `fmt.Sprint(x)` 也可以格式化生成并返回你所需要的字符串([第 4.4.3 节](04.3.md))。
|
||||||
|
|
||||||
**练习 4.6** [count_characters.go](exercises/chapter_4/count_characters.go)
|
**练习 4.6** [count_characters.go](exercises/chapter_4/count_characters.go)
|
||||||
|
|
||||||
|
@@ -75,7 +75,7 @@ func main() {
|
|||||||
|
|
||||||
It's equal to 100
|
It's equal to 100
|
||||||
|
|
||||||
在第 12.1 节,我们会使用 `switch` 语句判断从键盘输入的字符(详见[第 12.2 节](12.2.md) 的 [switch.go](.\examples\chapter_12\switch.go))。`switch` 语句的第二种形式是不提供任何被判断的值(实际上默认为判断是否为 `true`),然后在每个 `case` 分支中进行测试不同的条件。当任一分支的测试结果为 `true` 时,该分支的代码会被执行。这看起来非常像链式的 if-else 语句,但是在测试条件非常多的情况下,提供了可读性更好的书写方式。
|
在第 12.1 节,我们会使用 `switch` 语句判断从键盘输入的字符(详见[第 12.2 节](12.2.md) 的 [switch.go](./examples/chapter_12/switch.go))。`switch` 语句的第二种形式是不提供任何被判断的值(实际上默认为判断是否为 `true`),然后在每个 `case` 分支中进行测试不同的条件。当任一分支的测试结果为 `true` 时,该分支的代码会被执行。这看起来非常像链式的 if-else 语句,但是在测试条件非常多的情况下,提供了可读性更好的书写方式。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
switch {
|
switch {
|
||||||
|
@@ -46,7 +46,7 @@ func main() {
|
|||||||
for i, j := 0, N; i < j; i, j = i+1, j-1 {}
|
for i, j := 0, N; i < j; i, j = i+1, j-1 {}
|
||||||
```
|
```
|
||||||
|
|
||||||
这得益于 Go 语言具有的平行赋值的特性(可以查看[第 7 章](07.0.md) [string_reverse.go](.\examples\chapter_7\string_reverse.go) 中反转数组的示例)。
|
这得益于 Go 语言具有的平行赋值的特性(可以查看[第 7 章](07.0.md) [string_reverse.go](./examples/chapter_7/string_reverse.go) 中反转数组的示例)。
|
||||||
|
|
||||||
您可以将两个 for 循环嵌套起来:
|
您可以将两个 for 循环嵌套起来:
|
||||||
|
|
||||||
|
@@ -53,7 +53,7 @@ func main() {
|
|||||||
|
|
||||||
**特别注意** 使用标签和 `goto` 语句是不被鼓励的:它们会很快导致非常糟糕的程序设计,而且总有更加可读的替代方案来实现相同的需求。
|
**特别注意** 使用标签和 `goto` 语句是不被鼓励的:它们会很快导致非常糟糕的程序设计,而且总有更加可读的替代方案来实现相同的需求。
|
||||||
|
|
||||||
一个建议使用 `goto` 语句的示例会在[第 15.1 章](15.1.md) 的 [simple_tcp_server.go](.\examples\chapter_15\simple_tcp_server.go) 中出现:示例中在发生读取错误时,使用 goto 来跳出无限读取循环并关闭相应的客户端链接。
|
一个建议使用 `goto` 语句的示例会在[第 15.1 章](15.1.md) 的 [simple_tcp_server.go](./examples/chapter_15/simple_tcp_server.go) 中出现:示例中在发生读取错误时,使用 goto 来跳出无限读取循环并关闭相应的客户端链接。
|
||||||
|
|
||||||
定义但未使用标签会导致编译错误:`label … defined and not used`。
|
定义但未使用标签会导致编译错误:`label … defined and not used`。
|
||||||
|
|
||||||
|
@@ -84,7 +84,7 @@ func MultiPly3Nums(a int, b int, c int) int {
|
|||||||
|
|
||||||
`getX2AndX3` 与 `getX2AndX3_2` 两个函数演示了如何使用非命名返回值与命名返回值的特性。当需要返回多个非命名返回值时,需要使用 `()` 把它们括起来,比如 `(int, int)`。
|
`getX2AndX3` 与 `getX2AndX3_2` 两个函数演示了如何使用非命名返回值与命名返回值的特性。当需要返回多个非命名返回值时,需要使用 `()` 把它们括起来,比如 `(int, int)`。
|
||||||
|
|
||||||
命名返回值作为结果形参 (result parameters) 被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的 `return` 语句。需要注意的是,即使只有一个命名返回值,也需要使用 `()` 括起来(参考[第 6.6 节](06.6.md) 的 [fibonacci.go](.\examples\chapter_6\fibonacci.go) 函数)。
|
命名返回值作为结果形参 (result parameters) 被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的 `return` 语句。需要注意的是,即使只有一个命名返回值,也需要使用 `()` 括起来(参考[第 6.6 节](06.6.md) 的 [fibonacci.go](./examples/chapter_6/fibonacci.go) 函数)。
|
||||||
|
|
||||||
示例 6.3 [multiple_return.go](examples/chapter_6/multiple_return.go)
|
示例 6.3 [multiple_return.go](examples/chapter_6/multiple_return.go)
|
||||||
|
|
||||||
|
@@ -53,7 +53,7 @@ func min(s ...int) int {
|
|||||||
The minimum is: 0
|
The minimum is: 0
|
||||||
The minimum in the slice is: 1
|
The minimum in the slice is: 1
|
||||||
|
|
||||||
**练习 6.3** [varargs.go](exercises\chapter_6\varargs.go)
|
**练习 6.3** [varargs.go](exercises/chapter_6/varargs.go)
|
||||||
|
|
||||||
写一个函数,该函数接受一个变长参数并对每个元素进行换行打印。
|
写一个函数,该函数接受一个变长参数并对每个元素进行换行打印。
|
||||||
|
|
||||||
|
@@ -92,15 +92,15 @@ func RevSign(nr int) int {
|
|||||||
|
|
||||||
### 练习题
|
### 练习题
|
||||||
|
|
||||||
**练习 6.4** [fibonacci2.go](exercises\chapter_6\fibonacci2.go)
|
**练习 6.4** [fibonacci2.go](exercises/chapter_6/fibonacci2.go)
|
||||||
|
|
||||||
重写本节中生成斐波那契数列的程序并返回两个命名返回值(详见[第 6.2 节](06.2.md)),即数列中的位置和对应的值,例如 5 与 4,89 与 10。
|
重写本节中生成斐波那契数列的程序并返回两个命名返回值(详见[第 6.2 节](06.2.md)),即数列中的位置和对应的值,例如 5 与 4,89 与 10。
|
||||||
|
|
||||||
**练习 6.5** [10to1_recursive.go](exercises\chapter_6\10to1_recursive.go)
|
**练习 6.5** [10to1_recursive.go](exercises/chapter_6/10to1_recursive.go)
|
||||||
|
|
||||||
使用递归函数从 10 打印到 1。
|
使用递归函数从 10 打印到 1。
|
||||||
|
|
||||||
**练习 6.6** [factorial.go](exercises\chapter_6\factorial.go)
|
**练习 6.6** [factorial.go](exercises/chapter_6/factorial.go)
|
||||||
|
|
||||||
实现一个输出前 30 个整数的阶乘的程序。
|
实现一个输出前 30 个整数的阶乘的程序。
|
||||||
|
|
||||||
|
@@ -95,7 +95,7 @@ go func(i int) {
|
|||||||
|
|
||||||
这样闭包函数就能够被应用到整个集合的元素上,并修改它们的值。然后这些变量就可以用于表示或计算全局或平均值。
|
这样闭包函数就能够被应用到整个集合的元素上,并修改它们的值。然后这些变量就可以用于表示或计算全局或平均值。
|
||||||
|
|
||||||
**练习 6.9** [fibonacci_closure](exercises\chapter_6\fibonacci_closure.go)
|
**练习 6.9** [fibonacci_closure](exercises/chapter_6/fibonacci_closure.go)
|
||||||
|
|
||||||
不使用递归但使用闭包改写第 6.6 节中的斐波那契数列程序。
|
不使用递归但使用闭包改写第 6.6 节中的斐波那契数列程序。
|
||||||
|
|
||||||
|
@@ -138,15 +138,15 @@ func main() {
|
|||||||
|
|
||||||
**练习**
|
**练习**
|
||||||
|
|
||||||
练习7.1:[array_value.go](examples\chapter_7\array_value.go):
|
练习7.1:[array_value.go](examples/chapter_7/array_value.go):
|
||||||
|
|
||||||
证明当数组赋值时,发生了数组内存拷贝。
|
证明当数组赋值时,发生了数组内存拷贝。
|
||||||
|
|
||||||
练习7.2:[for_array.go](examples\chapter_7\for_array.go):
|
练习7.2:[for_array.go](examples/chapter_7/for_array.go):
|
||||||
|
|
||||||
写一个循环并用下标给数组赋值(从 0 到 15)并且将数组打印在屏幕上。
|
写一个循环并用下标给数组赋值(从 0 到 15)并且将数组打印在屏幕上。
|
||||||
|
|
||||||
练习7.3:[fibonacci_array.go](examples\chapter_7\fibonacci_array.go):
|
练习7.3:[fibonacci_array.go](examples/chapter_7/fibonacci_array.go):
|
||||||
|
|
||||||
在[第 6.6 节](06.6.md) 我们看到了一个递归计算 Fibonacci 数值的方法。但是通过数组我们可以更快的计算出 Fibonacci 数。完成该方法并打印出前 50 个 Fibonacci 数字。
|
在[第 6.6 节](06.6.md) 我们看到了一个递归计算 Fibonacci 数值的方法。但是通过数组我们可以更快的计算出 Fibonacci 数。完成该方法并打印出前 50 个 Fibonacci 数字。
|
||||||
|
|
||||||
|
@@ -176,15 +176,15 @@ func FindFileDigits(filename string) []byte {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**练习 7.12** [split_string.go](exercises\chapter_7\split_string.go)
|
**练习 7.12** [split_string.go](exercises/chapter_7/split_string.go)
|
||||||
|
|
||||||
编写一个函数,要求其接受两个参数,原始字符串 `str` 和分割索引 `i`,然后返回两个分割后的字符串。
|
编写一个函数,要求其接受两个参数,原始字符串 `str` 和分割索引 `i`,然后返回两个分割后的字符串。
|
||||||
|
|
||||||
**练习 7.13** [string_split2.go](exercises\chapter_7\string_split2.go)
|
**练习 7.13** [string_split2.go](exercises/chapter_7/string_split2.go)
|
||||||
|
|
||||||
假设有字符串 `str`,那么 `str[len(str)/2:] + str[:len(str)/2]` 的结果是什么?
|
假设有字符串 `str`,那么 `str[len(str)/2:] + str[:len(str)/2]` 的结果是什么?
|
||||||
|
|
||||||
**练习 7.14** [string_reverse.go](exercises\chapter_7\string_reverse.go)
|
**练习 7.14** [string_reverse.go](exercises/chapter_7/string_reverse.go)
|
||||||
|
|
||||||
编写一个程序,要求能够反转字符串,即将 `"Google"` 转换成 `"elgooG"`(提示:使用 `[]byte` 类型的切片)。
|
编写一个程序,要求能够反转字符串,即将 `"Google"` 转换成 `"elgooG"`(提示:使用 `[]byte` 类型的切片)。
|
||||||
|
|
||||||
@@ -192,15 +192,15 @@ func FindFileDigits(filename string) []byte {
|
|||||||
|
|
||||||
如果您想要反转 Unicode 编码的字符串,请使用 `[]int32` 类型的切片。
|
如果您想要反转 Unicode 编码的字符串,请使用 `[]int32` 类型的切片。
|
||||||
|
|
||||||
**练习 7.15** [Q29_uniq.go](exercises\chapter_7\uniq.go)
|
**练习 7.15** [Q29_uniq.go](exercises/chapter_7/uniq.go)
|
||||||
|
|
||||||
编写一个程序,要求能够遍历一个字符数组,并将当前字符和前一个字符不相同的字符拷贝至另一个数组。
|
编写一个程序,要求能够遍历一个字符数组,并将当前字符和前一个字符不相同的字符拷贝至另一个数组。
|
||||||
|
|
||||||
**练习 7.16** [bubblesort.go](exercises\chapter_7\bubblesort.go)
|
**练习 7.16** [bubblesort.go](exercises/chapter_7/bubblesort.go)
|
||||||
|
|
||||||
编写一个程序,使用冒泡排序的方法排序一个包含整数的切片(算法的定义可参考 [维基百科](http://en.wikipedia.org/wiki/Bubble_sort))。
|
编写一个程序,使用冒泡排序的方法排序一个包含整数的切片(算法的定义可参考 [维基百科](http://en.wikipedia.org/wiki/Bubble_sort))。
|
||||||
|
|
||||||
**练习 7.17** [map_function.go](exercises\chapter_7\map_function.go)
|
**练习 7.17** [map_function.go](exercises/chapter_7/map_function.go)
|
||||||
|
|
||||||
在函数式编程语言中,一个 map-function 是指能够接受一个函数原型和一个列表,并使用列表中的值依次执行函数原型,公式为:`map ( F(), (e1,e2, . . . ,en) ) = ( F(e1), F(e2), ... F(en) )`。
|
在函数式编程语言中,一个 map-function 是指能够接受一个函数原型和一个列表,并使用列表中的值依次执行函数原型,公式为:`map ( F(), (e1,e2, . . . ,en) ) = ( F(e1), F(e2), ... F(en) )`。
|
||||||
|
|
||||||
|
@@ -62,7 +62,7 @@ for key := range capitals {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**练习 8.1** [map_days.go](exercises\chapter_8\map_days.go)
|
**练习 8.1** [map_days.go](exercises/chapter_8/map_days.go)
|
||||||
|
|
||||||
创建一个 `map` 来保存每周 7 天的名字,将它们打印出来并且测试是否存在 `"Tuesday"` 和 `"Hollyday"`。
|
创建一个 `map` 来保存每周 7 天的名字,将它们打印出来并且测试是否存在 `"Tuesday"` 和 `"Hollyday"`。
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@ func main() {
|
|||||||
|
|
||||||
如果原始 value 值不唯一那这么做肯定会出问题;这种情况下不会报错,但是当遇到不唯一的 key 时应当直接停止对调,且此时对调后的 `map` 很可能没有包含原 `map` 的所有键值对!一种解决方法就是仔细检查唯一性并且使用多值 `map`,比如使用 `map[int][]string` 类型。
|
如果原始 value 值不唯一那这么做肯定会出问题;这种情况下不会报错,但是当遇到不唯一的 key 时应当直接停止对调,且此时对调后的 `map` 很可能没有包含原 `map` 的所有键值对!一种解决方法就是仔细检查唯一性并且使用多值 `map`,比如使用 `map[int][]string` 类型。
|
||||||
|
|
||||||
**练习 8.2** [map_drinks.go](exercises\chapter_8\map_drinks.go)
|
**练习 8.2** [map_drinks.go](exercises/chapter_8/map_drinks.go)
|
||||||
|
|
||||||
构造一个将英文饮料名映射为法语(或者任意你的母语)的集合;先打印所有的饮料,然后打印原名和翻译后的名字。接下来按照英文名排序后再打印出来。
|
构造一个将英文饮料名映射为法语(或者任意你的母语)的集合;先打印所有的饮料,然后打印原名和翻译后的名字。接下来按照英文名排序后再打印出来。
|
||||||
|
|
||||||
|
@@ -80,11 +80,11 @@ for e := l.Front(); e != nil; e = e.Next() {
|
|||||||
|
|
||||||
`exp` 包中有许多将被编译为新包的实验性的包。在下次稳定版本发布的时候,它们将成为独立的包。如果前一个版本已经存在了,它们将被作为过时的包被回收。然而 Go1.0 发布的时候并没有包含过时或者实验性的包。
|
`exp` 包中有许多将被编译为新包的实验性的包。在下次稳定版本发布的时候,它们将成为独立的包。如果前一个版本已经存在了,它们将被作为过时的包被回收。然而 Go1.0 发布的时候并没有包含过时或者实验性的包。
|
||||||
|
|
||||||
**练习 9.1** [Q20_linked_list.go](exercises\chapter_9\dlinked_list.go)
|
**练习 9.1** [Q20_linked_list.go](exercises/chapter_9/dlinked_list.go)
|
||||||
|
|
||||||
使用 `container/list` 包实现一个双向链表,将 `101`、`102` 和 `103` 放入其中并打印出来。
|
使用 `container/list` 包实现一个双向链表,将 `101`、`102` 和 `103` 放入其中并打印出来。
|
||||||
|
|
||||||
**练习 9.2** [size_int.go](exercises\chapter_9\size_int.go)
|
**练习 9.2** [size_int.go](exercises/chapter_9/size_int.go)
|
||||||
|
|
||||||
通过使用 `unsafe` 包中的方法来测试你电脑上一个整型变量占用多少个字节。
|
通过使用 `unsafe` 包中的方法来测试你电脑上一个整型变量占用多少个字节。
|
||||||
|
|
||||||
|
@@ -152,7 +152,7 @@ a)一个包能分成多个源文件么?
|
|||||||
|
|
||||||
b)一个源文件是否能包含多个包?
|
b)一个源文件是否能包含多个包?
|
||||||
|
|
||||||
**练习 9.3** [main_greetings.go](exercises\chapter_9\main_greetings.go)
|
**练习 9.3** [main_greetings.go](exercises/chapter_9/main_greetings.go)
|
||||||
|
|
||||||
创建一个程序 main_greetings.go 能够和用户说 `"Good Day"` 或者 `"Good Night"`。不同的问候应该放到单独的 `greetings` 包中。
|
创建一个程序 main_greetings.go 能够和用户说 `"Good Day"` 或者 `"Good Night"`。不同的问候应该放到单独的 `greetings` 包中。
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ b)一个源文件是否能包含多个包?
|
|||||||
|
|
||||||
使用 main_greetings 作出合适的问候(提示:使用 `time` 包)。
|
使用 main_greetings 作出合适的问候(提示:使用 `time` 包)。
|
||||||
|
|
||||||
**练习 9.4** 创建一个程序 [main_oddven.go](exercises\chapter_9\main_oddeven.go) 判断前 100 个整数是不是偶数,将判断所用的函数编写在 `even` 包里。
|
**练习 9.4** 创建一个程序 [main_oddven.go](exercises/chapter_9/main_oddeven.go) 判断前 100 个整数是不是偶数,将判断所用的函数编写在 `even` 包里。
|
||||||
|
|
||||||
**练习 9.5** 使用[第 6.6 节](06.6.md)的斐波那契程序:
|
**练习 9.5** 使用[第 6.6 节](06.6.md)的斐波那契程序:
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ b)一个源文件是否能包含多个包?
|
|||||||
|
|
||||||
2)扩展 `fibo` 包将通过调用斐波那契的时候,操作也作为一个参数。实验 `"+"` 和 `"*"`
|
2)扩展 `fibo` 包将通过调用斐波那契的时候,操作也作为一个参数。实验 `"+"` 和 `"*"`
|
||||||
|
|
||||||
[main_fibo.go](exercises\chapter_9\main_fibo.go) / [fibonacci.go](exercises/chapter_6/fibonacci.go)
|
[main_fibo.go](exercises/chapter_9/main_fibo.go) / [fibonacci.go](exercises/chapter_6/fibonacci.go)
|
||||||
|
|
||||||
## 链接
|
## 链接
|
||||||
|
|
||||||
|
@@ -278,7 +278,7 @@ func main() {
|
|||||||
|
|
||||||
{5} {5} {5}
|
{5} {5} {5}
|
||||||
|
|
||||||
**练习 10.1** [vcard.go](exercises\chapter_10\vcard.go):
|
**练习 10.1** [vcard.go](exercises/chapter_10/vcard.go):
|
||||||
|
|
||||||
定义结构体 `Address` 和 `VCard`,后者包含一个人的名字、地址编号、出生日期和图像,试着选择正确的数据类型。构建一个自己的 `vcard` 并打印它的内容。
|
定义结构体 `Address` 和 `VCard`,后者包含一个人的名字、地址编号、出生日期和图像,试着选择正确的数据类型。构建一个自己的 `vcard` 并打印它的内容。
|
||||||
|
|
||||||
@@ -287,15 +287,15 @@ func main() {
|
|||||||
第二种会好点,因为它占用内存少。包含一个名字和两个指向地址的指针的 Address 结构体可以使用 %v 打印:
|
第二种会好点,因为它占用内存少。包含一个名字和两个指向地址的指针的 Address 结构体可以使用 %v 打印:
|
||||||
{Kersschot 0x126d2b80 0x126d2be0}
|
{Kersschot 0x126d2b80 0x126d2be0}
|
||||||
|
|
||||||
**练习 10.2** [personex1.go](exercises\chapter_10\personex1.go):
|
**练习 10.2** [personex1.go](exercises/chapter_10/personex1.go):
|
||||||
|
|
||||||
修改 personex1.go,使它的参数 `upPerson` 不是一个指针,解释下二者的区别。
|
修改 personex1.go,使它的参数 `upPerson` 不是一个指针,解释下二者的区别。
|
||||||
|
|
||||||
**练习 10.3** [point.go](exercises\chapter_10\point.go):
|
**练习 10.3** [point.go](exercises/chapter_10/point.go):
|
||||||
|
|
||||||
使用坐标 `X`、`Y` 定义一个二维 `Point` 结构体。同样地,对一个三维点使用它的极坐标定义一个 `Polar` 结构体。实现一个 `Abs()` 方法来计算一个 `Point` 表示的向量的长度,实现一个 `Scale()` 方法,它将点的坐标乘以一个尺度因子(提示:使用 `math` 包里的 `Sqrt()` 函数)(function Scale that multiplies the coordinates of a point with a scale factor)。
|
使用坐标 `X`、`Y` 定义一个二维 `Point` 结构体。同样地,对一个三维点使用它的极坐标定义一个 `Polar` 结构体。实现一个 `Abs()` 方法来计算一个 `Point` 表示的向量的长度,实现一个 `Scale()` 方法,它将点的坐标乘以一个尺度因子(提示:使用 `math` 包里的 `Sqrt()` 函数)(function Scale that multiplies the coordinates of a point with a scale factor)。
|
||||||
|
|
||||||
**练习 10.4** [rectangle.go](exercises\chapter_10\rectangle.go):
|
**练习 10.4** [rectangle.go](exercises/chapter_10/rectangle.go):
|
||||||
|
|
||||||
定义一个 `Rectangle` 结构体,它的长和宽是 `int` 类型,并定义方法 `Area()` 和 `Perimeter()`,然后进行测试。
|
定义一个 `Rectangle` 结构体,它的长和宽是 `int` 类型,并定义方法 `Area()` 和 `Perimeter()`,然后进行测试。
|
||||||
|
|
||||||
|
@@ -92,7 +92,7 @@ func main() {
|
|||||||
1 2 3 4
|
1 2 3 4
|
||||||
{1 2}
|
{1 2}
|
||||||
|
|
||||||
**练习 10.5** [anonymous_struct.go](exercises\chapter_10\anonymous_struct.go):
|
**练习 10.5** [anonymous_struct.go](exercises/chapter_10/anonymous_struct.go):
|
||||||
|
|
||||||
创建一个结构体,它有一个具名的 `float32` 字段,2 个匿名字段,类型分别是 `int` 和 `string`。通过结构体字面量新建一个结构体实例并打印它的内容。
|
创建一个结构体,它有一个具名的 `float32` 字段,2 个匿名字段,类型分别是 `int` 和 `string`。通过结构体字面量新建一个结构体实例并打印它的内容。
|
||||||
|
|
||||||
|
@@ -103,11 +103,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**练习 10.6** [employee_salary.go](exercises\chapter_10\employee_salary.go)
|
**练习 10.6** [employee_salary.go](exercises/chapter_10/employee_salary.go)
|
||||||
|
|
||||||
定义结构体 `employee`,它有一个 `salary` 字段,给这个结构体定义一个方法 `giveRaise` 来按照指定的百分比增加薪水。
|
定义结构体 `employee`,它有一个 `salary` 字段,给这个结构体定义一个方法 `giveRaise` 来按照指定的百分比增加薪水。
|
||||||
|
|
||||||
**练习 10.7** [iteration_list.go](exercises\chapter_10\iteration_list.go)
|
**练习 10.7** [iteration_list.go](exercises/chapter_10/iteration_list.go)
|
||||||
|
|
||||||
下面这段代码有什么错?
|
下面这段代码有什么错?
|
||||||
|
|
||||||
@@ -415,7 +415,7 @@ func (n *NamedPoint) Abs() float64 {
|
|||||||
|
|
||||||
结构体内嵌和自己在同一个包中的结构体时,可以彼此访问对方所有的字段和方法。
|
结构体内嵌和自己在同一个包中的结构体时,可以彼此访问对方所有的字段和方法。
|
||||||
|
|
||||||
**练习 10.8** [inheritance_car.go](exercises\chapter_10\inheritance_car.go)
|
**练习 10.8** [inheritance_car.go](exercises/chapter_10/inheritance_car.go)
|
||||||
|
|
||||||
创建一个上面 `Car` 和 `Engine` 可运行的例子,并且给 `Car` 类型一个 `wheelCount` 字段和一个 `numberOfWheels()` 方法。
|
创建一个上面 `Car` 和 `Engine` 可运行的例子,并且给 `Car` 类型一个 `wheelCount` 字段和一个 `numberOfWheels()` 方法。
|
||||||
|
|
||||||
@@ -581,17 +581,17 @@ func main() {
|
|||||||
It exhibits behavior of a Camera: Click
|
It exhibits behavior of a Camera: Click
|
||||||
It works like a Phone too: Ring Ring
|
It works like a Phone too: Ring Ring
|
||||||
|
|
||||||
**练习 10.9** [point_methods.go](exercises\chapter_10\point_methods.go):
|
**练习 10.9** [point_methods.go](exercises/chapter_10/point_methods.go):
|
||||||
|
|
||||||
从 `point.go` 开始([第 10.1 节](10.1)的练习):使用方法来实现 `Abs()` 和 `Scale()`函数,`Point` 作为方法的接收者类型。也为 `Point3` 和 `Polar` 实现 `Abs()` 方法。完成了 `point.go` 中同样的事情,只是这次通过方法。
|
从 `point.go` 开始([第 10.1 节](10.1)的练习):使用方法来实现 `Abs()` 和 `Scale()`函数,`Point` 作为方法的接收者类型。也为 `Point3` 和 `Polar` 实现 `Abs()` 方法。完成了 `point.go` 中同样的事情,只是这次通过方法。
|
||||||
|
|
||||||
**练习 10.10** [inherit_methods.go](exercises\chapter_10\inherit_methods.go):
|
**练习 10.10** [inherit_methods.go](exercises/chapter_10/inherit_methods.go):
|
||||||
|
|
||||||
定义一个结构体类型 `Base`,它包含一个字段 `id`,方法 `Id()` 返回 `id`,方法 `SetId()` 修改 `id`。结构体类型 `Person` 包含 `Base`,及 `FirstName` 和 `LastName` 字段。结构体类型 `Employee` 包含一个 `Person` 和 `salary` 字段。
|
定义一个结构体类型 `Base`,它包含一个字段 `id`,方法 `Id()` 返回 `id`,方法 `SetId()` 修改 `id`。结构体类型 `Person` 包含 `Base`,及 `FirstName` 和 `LastName` 字段。结构体类型 `Employee` 包含一个 `Person` 和 `salary` 字段。
|
||||||
|
|
||||||
创建一个 `employee` 实例,然后显示它的 `id`。
|
创建一个 `employee` 实例,然后显示它的 `id`。
|
||||||
|
|
||||||
**练习 10.11** [magic.go](exercises\chapter_10\magic.go):
|
**练习 10.11** [magic.go](exercises/chapter_10/magic.go):
|
||||||
|
|
||||||
首先预测一下下面程序的结果,然后动手实验下:
|
首先预测一下下面程序的结果,然后动手实验下:
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ func (t TT) String() string {
|
|||||||
t.String()
|
t.String()
|
||||||
```
|
```
|
||||||
|
|
||||||
**练习 10.12** [type_string.go](exercises\chapter_10\type_string.go)
|
**练习 10.12** [type_string.go](exercises/chapter_10/type_string.go)
|
||||||
|
|
||||||
给定结构体类型 `T`:
|
给定结构体类型 `T`:
|
||||||
|
|
||||||
@@ -72,19 +72,19 @@ type T struct {
|
|||||||
|
|
||||||
值 `t`: `t := &T{7, -2.35, "abc\tdef"}`。给 T 定义 `String()`,使得 `fmt.Printf("%v\n", t)` 输出:`7 / -2.350000 / "abc\tdef"`。
|
值 `t`: `t := &T{7, -2.35, "abc\tdef"}`。给 T 定义 `String()`,使得 `fmt.Printf("%v\n", t)` 输出:`7 / -2.350000 / "abc\tdef"`。
|
||||||
|
|
||||||
**练习 10.13** [celsius.go](exercises\chapter_10\celsius.go)
|
**练习 10.13** [celsius.go](exercises/chapter_10/celsius.go)
|
||||||
|
|
||||||
为 `float64` 定义一个别名类型 `Celsius`,并给它定义 `String()`,它输出一个十进制数和 °C 表示的温度值。
|
为 `float64` 定义一个别名类型 `Celsius`,并给它定义 `String()`,它输出一个十进制数和 °C 表示的温度值。
|
||||||
|
|
||||||
**练习 10.14** [days.go](exercises\chapter_10\days.go)
|
**练习 10.14** [days.go](exercises/chapter_10/days.go)
|
||||||
|
|
||||||
为 `int` 定义一个别名类型 `Day`,定义一个字符串数组它包含一周七天的名字,为类型 `Day` 定义 `String()` 方法,它输出星期几的名字。使用 `iota` 定义一个枚举常量用于表示一周的中每天(MO、TU...)。
|
为 `int` 定义一个别名类型 `Day`,定义一个字符串数组它包含一周七天的名字,为类型 `Day` 定义 `String()` 方法,它输出星期几的名字。使用 `iota` 定义一个枚举常量用于表示一周的中每天(MO、TU...)。
|
||||||
|
|
||||||
**练习 10.15** [timezones.go](exercises\chapter_10\timezones.go)
|
**练习 10.15** [timezones.go](exercises/chapter_10/timezones.go)
|
||||||
|
|
||||||
为 `int` 定义别名类型 `TZ`,定义一些常量表示时区,比如 UTC,定义一个 `map`,它将时区的缩写映射为它的全称,比如:`UTC -> "Universal Greenwich time"`。为类型 `TZ` 定义 `String()` 方法,它输出时区的全称。
|
为 `int` 定义别名类型 `TZ`,定义一些常量表示时区,比如 UTC,定义一个 `map`,它将时区的缩写映射为它的全称,比如:`UTC -> "Universal Greenwich time"`。为类型 `TZ` 定义 `String()` 方法,它输出时区的全称。
|
||||||
|
|
||||||
**练习 10.16** [stack_arr.go](exercises\chapter_10\stack_arr.go) / [stack_struct.go](exercises\chapter_10\stack_struct.go)
|
**练习 10.16** [stack_arr.go](exercises/chapter_10/stack_arr.go) / [stack_struct.go](exercises/chapter_10/stack_struct.go)
|
||||||
|
|
||||||
实现栈 (stack) 数据结构:
|
实现栈 (stack) 数据结构:
|
||||||
|
|
||||||
@@ -101,9 +101,9 @@ type T struct {
|
|||||||
|
|
||||||
为栈定义一个 `Stack` 类型,并为它定义 `Push` 和 `Pop` 方法,再为它定义 `String()` 方法(用于调试)输出栈的内容,比如:`[0:i] [1:j] [2:k] [3:l]`。
|
为栈定义一个 `Stack` 类型,并为它定义 `Push` 和 `Pop` 方法,再为它定义 `String()` 方法(用于调试)输出栈的内容,比如:`[0:i] [1:j] [2:k] [3:l]`。
|
||||||
|
|
||||||
1)[stack_arr.go](exercises\chapter_10\stack_arr.go):使用长度为 4 的 int 数组作为底层数据结构。
|
1)[stack_arr.go](exercises/chapter_10/stack_arr.go):使用长度为 4 的 int 数组作为底层数据结构。
|
||||||
|
|
||||||
2) [stack_struct.go](exercises\chapter_10\stack_struct.go):使用包含一个索引和一个 `int` 数组的结构体作为底层数据结构,索引表示第一个空闲的位置。
|
2) [stack_struct.go](exercises/chapter_10/stack_struct.go):使用包含一个索引和一个 `int` 数组的结构体作为底层数据结构,索引表示第一个空闲的位置。
|
||||||
|
|
||||||
3)使用常量 `LIMIT` 代替上面表示元素个数的 4 重新实现上面的 1)和 2),使它们更具有一般性。
|
3)使用常量 `LIMIT` 代替上面表示元素个数的 4 重新实现上面的 1)和 2),使它们更具有一般性。
|
||||||
|
|
||||||
|
@@ -26,9 +26,9 @@ runtime.SetFinalizer(obj, func(obj *typeObj))
|
|||||||
|
|
||||||
在对象被 GC 进程选中并从内存中移除以前,`SetFinalizer` 都不会执行,即使程序正常结束或者发生错误。
|
在对象被 GC 进程选中并从内存中移除以前,`SetFinalizer` 都不会执行,即使程序正常结束或者发生错误。
|
||||||
|
|
||||||
**练习 10.17** [main_stack.go](exercises\chapter_10\main_stack.go)
|
**练习 10.17** [main_stack.go](exercises/chapter_10/main_stack.go)
|
||||||
|
|
||||||
从练习 10.16 开始(它基于结构体实现了一个栈结构),为栈的实现 ([stack_struct.go](exercises\chapter_10\stack_struct.go)) 创建一个单独的包 `stack`,并从 `main` 包 `main.stack.go` 中调用它。
|
从练习 10.16 开始(它基于结构体实现了一个栈结构),为栈的实现 ([stack_struct.go](exercises/chapter_10/stack_struct.go)) 创建一个单独的包 `stack`,并从 `main` 包 `main.stack.go` 中调用它。
|
||||||
|
|
||||||
## 链接
|
## 链接
|
||||||
|
|
||||||
|
@@ -236,15 +236,15 @@ type Reader interface {
|
|||||||
|
|
||||||
有的时候,也会以一种稍微不同的方式来使用接口这个词:从某个类型的角度来看,它的接口指的是:它的所有导出方法,只不过没有显式地为这些导出方法额外定一个接口而已。
|
有的时候,也会以一种稍微不同的方式来使用接口这个词:从某个类型的角度来看,它的接口指的是:它的所有导出方法,只不过没有显式地为这些导出方法额外定一个接口而已。
|
||||||
|
|
||||||
**练习 11.1** [simple_interface.go](exercises\chapter_11\simple_interface.go):
|
**练习 11.1** [simple_interface.go](exercises/chapter_11/simple_interface.go):
|
||||||
|
|
||||||
定义一个接口 `Simpler`,它有一个 `Get()` 方法和一个 `Set()`,`Get()` 返回一个整型值,`Set()` 有一个整型参数。创建一个结构体类型 `Simple` 实现这个接口。
|
定义一个接口 `Simpler`,它有一个 `Get()` 方法和一个 `Set()`,`Get()` 返回一个整型值,`Set()` 有一个整型参数。创建一个结构体类型 `Simple` 实现这个接口。
|
||||||
|
|
||||||
接着定一个函数,它有一个 `Simpler` 类型的参数,调用参数的 `Get()` 和 `Set()` 方法。在 `main` 函数里调用这个函数,看看它是否可以正确运行。
|
接着定一个函数,它有一个 `Simpler` 类型的参数,调用参数的 `Get()` 和 `Set()` 方法。在 `main` 函数里调用这个函数,看看它是否可以正确运行。
|
||||||
|
|
||||||
**练习 11.2** [interfaces_poly2.go](exercises\chapter_11\interfaces_poly2.go):
|
**练习 11.2** [interfaces_poly2.go](exercises/chapter_11/interfaces_poly2.go):
|
||||||
|
|
||||||
a) 扩展 [interfaces_poly.go](exercises\chapter_11\interfaces_poly.go) 中的例子,添加一个 `Circle` 类型
|
a) 扩展 [interfaces_poly.go](exercises/chapter_11/interfaces_poly.go) 中的例子,添加一个 `Circle` 类型
|
||||||
|
|
||||||
b) 使用一个抽象类型 `Shape`(没有字段) 实现同样的功能,它实现接口 `Shaper`,然后在其他类型里内嵌此类型。扩展 [10.6.5](10.6.md) 中的例子来说明覆写。
|
b) 使用一个抽象类型 `Shape`(没有字段) 实现同样的功能,它实现接口 `Shaper`,然后在其他类型里内嵌此类型。扩展 [10.6.5](10.6.md) 中的例子来说明覆写。
|
||||||
|
|
||||||
|
@@ -274,7 +274,7 @@ type ReaderWriter struct {
|
|||||||
|
|
||||||
**练习 11.11**:[map_function_interface.go](exercises/chapter_11/map_function_interface.go):
|
**练习 11.11**:[map_function_interface.go](exercises/chapter_11/map_function_interface.go):
|
||||||
|
|
||||||
在练习 7.13 中我们定义了一个 `map()` 函数来使用 `int` 切片 ([map_function.go](exercises\chapter_7\map_function.go))。
|
在练习 7.13 中我们定义了一个 `map()` 函数来使用 `int` 切片 ([map_function.go](exercises/chapter_7/map_function.go))。
|
||||||
|
|
||||||
通过空接口和类型断言,现在我们可以写一个可以应用于许多类型的*泛型*的 `map()` 函数,为 `int` 和 `string` 构建一个把 `int` 值加倍和将字符串值与其自身连接(译者注:即 `"abc"` 变成 `"abcabc"` )的 `map()` 函数 `mapFunc()`。
|
通过空接口和类型断言,现在我们可以写一个可以应用于许多类型的*泛型*的 `map()` 函数,为 `int` 和 `string` 构建一个把 `int` 值加倍和将字符串值与其自身连接(译者注:即 `"abc"` 变成 `"abcabc"` )的 `map()` 函数 `mapFunc()`。
|
||||||
|
|
||||||
|
@@ -66,7 +66,7 @@ func classifier(items ...interface{}) {
|
|||||||
|
|
||||||
在示例 12.17 ([xml.go](examples/chapter_12/xml.go)) 中解析 XML 文档时,我们就会用到 `type-switch`。
|
在示例 12.17 ([xml.go](examples/chapter_12/xml.go)) 中解析 XML 文档时,我们就会用到 `type-switch`。
|
||||||
|
|
||||||
**练习 11.4** [simple_interface2.go](exercises\chapter_11\simple_interface2.go):
|
**练习 11.4** [simple_interface2.go](exercises/chapter_11/simple_interface2.go):
|
||||||
|
|
||||||
接着练习 11.1 中的内容,创建第二个类型 `RSimple`,它也实现了接口 `Simpler`,写一个函数 `fi()`,使它可以区分 `Simple` 和 `RSimple` 类型的变量。
|
接着练习 11.1 中的内容,创建第二个类型 `RSimple`,它也实现了接口 `Simpler`,写一个函数 `fi()`,使它可以区分 `Simple` 和 `RSimple` 类型的变量。
|
||||||
|
|
||||||
|
@@ -45,7 +45,7 @@ a := sort.IntArray(data) //conversion to type IntArray from package sort
|
|||||||
sort.Sort(a)
|
sort.Sort(a)
|
||||||
```
|
```
|
||||||
|
|
||||||
完整的、可运行的代码可以在 [sort.go](examples\chapter_11\sort\sort.go) 和 [sortmain.go](examples\chapter_11\sortmain.go) 里找到。
|
完整的、可运行的代码可以在 [sort.go](examples/chapter_11/sort/sort.go) 和 [sortmain.go](examples/chapter_11/sortmain.go) 里找到。
|
||||||
|
|
||||||
同样的原理,排序函数可以用于一个浮点型数组,一个字符串数组,或者一个表示每周各天的结构体 `dayArray`。
|
同样的原理,排序函数可以用于一个浮点型数组,一个字符串数组,或者一个表示每周各天的结构体 `dayArray`。
|
||||||
|
|
||||||
@@ -194,17 +194,17 @@ type Interface interface {
|
|||||||
|
|
||||||
这个接口总结了需要用于排序的抽象方法,函数 `Sort(data Interface)` 用来对此类对象进行排序,可以用它们来实现对其他类型的数据(非基本类型)进行排序。在上面的例子中,我们也是这么做的,不仅可以对 `int` 和 `string` 序列进行排序,也可以对用户自定义类型 `dayArray` 进行排序。
|
这个接口总结了需要用于排序的抽象方法,函数 `Sort(data Interface)` 用来对此类对象进行排序,可以用它们来实现对其他类型的数据(非基本类型)进行排序。在上面的例子中,我们也是这么做的,不仅可以对 `int` 和 `string` 序列进行排序,也可以对用户自定义类型 `dayArray` 进行排序。
|
||||||
|
|
||||||
**练习 11.5** [interfaces_ext.go](exercises\chapter_11\interfaces_ext.go):
|
**练习 11.5** [interfaces_ext.go](exercises/chapter_11/interfaces_ext.go):
|
||||||
|
|
||||||
a). 继续扩展程序,定义类型 `Triangle`,让它实现 `AreaInterface` 接口。通过计算一个特定三角形的面积来进行测试(三角形面积=0.5 * (底 * 高))
|
a). 继续扩展程序,定义类型 `Triangle`,让它实现 `AreaInterface` 接口。通过计算一个特定三角形的面积来进行测试(三角形面积=0.5 * (底 * 高))
|
||||||
|
|
||||||
b). 定义一个新接口 `PeriInterface`,它有一个 `Perimeter` 方法。让 `Square` 实现这个接口,并通过一个 `Square` 示例来测试它。
|
b). 定义一个新接口 `PeriInterface`,它有一个 `Perimeter` 方法。让 `Square` 实现这个接口,并通过一个 `Square` 示例来测试它。
|
||||||
|
|
||||||
**练习 11.6** [point_interfaces.go](exercises\chapter_11\point_interfaces.go):
|
**练习 11.6** [point_interfaces.go](exercises/chapter_11/point_interfaces.go):
|
||||||
|
|
||||||
继续 [10.3](10.3.md) 中的练习 [point_methods.go](exercises\chapter_10\point_methods.go),定义接口 `Magnitude`,它有一个方法 `Abs()`。让 `Point`、`Point3` 及 `Polar` 实现此接口。通过接口类型变量使用方法做 point.go 中同样的事情。
|
继续 [10.3](10.3.md) 中的练习 [point_methods.go](exercises/chapter_10/point_methods.go),定义接口 `Magnitude`,它有一个方法 `Abs()`。让 `Point`、`Point3` 及 `Polar` 实现此接口。通过接口类型变量使用方法做 point.go 中同样的事情。
|
||||||
|
|
||||||
**练习 11.7** [float_sort.go](exercises\chapter_11\float_sort.go) / [float_sortmain.go](exercises\chapter_11\float_sortmain.go):
|
**练习 11.7** [float_sort.go](exercises/chapter_11/float_sort.go) / [float_sortmain.go](exercises/chapter_11/float_sortmain.go):
|
||||||
|
|
||||||
类似 11.7 和示例 11.3/4,定义一个包 `float64`,并在包里定义类型 `Float64Array`,然后让它实现 `Sorter` 接口用来对 `float64` 数组进行排序。
|
类似 11.7 和示例 11.3/4,定义一个包 `float64`,并在包里定义类型 `Float64Array`,然后让它实现 `Sorter` 接口用来对 `float64` 数组进行排序。
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ b). 定义一个新接口 `PeriInterface`,它有一个 `Perimeter` 方法。
|
|||||||
|
|
||||||
在主程序中新建一个此类型的变量,然后对它排序并进行测试。
|
在主程序中新建一个此类型的变量,然后对它排序并进行测试。
|
||||||
|
|
||||||
**练习 11.8** [sort.go](exercises\chapter_11\sort\sort.go) / [sort_persons.go](exercises\chapter_11\sort_persons.go):
|
**练习 11.8** [sort.go](exercises/chapter_11/sort/sort.go) / [sort_persons.go](exercises/chapter_11/sort_persons.go):
|
||||||
|
|
||||||
定义一个结构体 `Person`,它有两个字段:`firstName` 和 `lastName`,为 `[]Person` 定义类型 `Persons` 。让 `Persons` 实现 `Sorter` 接口并进行测试。
|
定义一个结构体 `Person`,它有两个字段:`firstName` 和 `lastName`,为 `[]Person` 定义类型 `Persons` 。让 `Persons` 实现 `Sorter` 接口并进行测试。
|
||||||
|
|
||||||
|
@@ -105,7 +105,7 @@ func main() {
|
|||||||
|
|
||||||
any hello is a special String!
|
any hello is a special String!
|
||||||
|
|
||||||
**练习 11.9** [simple_interface3.go](exercises\chapter_11\simple_interface3.go):
|
**练习 11.9** [simple_interface3.go](exercises/chapter_11/simple_interface3.go):
|
||||||
|
|
||||||
继续练习 11.2,在它中添加一个 `gI()` 函数,它不再接受 `Simpler` 类型的参数,而是接受一个空接口参数。然后通过类型断言判断参数是否是 `Simpler` 类型。最后在 `main` 使用 `gI()` 取代 `fI()` 函数并调用它。确保你的代码足够安全。
|
继续练习 11.2,在它中添加一个 `gI()` 函数,它不再接受 `Simpler` 类型的参数,而是接受一个空接口参数。然后通过类型断言判断参数是否是 `Simpler` 类型。最后在 `main` 使用 `gI()` 取代 `fI()` 函数并调用它。确保你的代码足够安全。
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ func (p *Vector) Set(i int, e Element) {
|
|||||||
|
|
||||||
`Vector` 中存储的所有元素都是 `Element` 类型,要得到它们的原始类型(unboxing:拆箱)需要用到类型断言。TODO:The compiler rejects assertions guaranteed to fail,类型断言总是在运行时才执行,因此它会产生运行时错误。
|
`Vector` 中存储的所有元素都是 `Element` 类型,要得到它们的原始类型(unboxing:拆箱)需要用到类型断言。TODO:The compiler rejects assertions guaranteed to fail,类型断言总是在运行时才执行,因此它会产生运行时错误。
|
||||||
|
|
||||||
**练习 11.10** [min_interface.go](exercises\chapter_11\min_interface.go) / [minmain.go](exercises\chapter_11\minmain.go):
|
**练习 11.10** [min_interface.go](exercises/chapter_11/min_interface.go) / [minmain.go](exercises/chapter_11/minmain.go):
|
||||||
|
|
||||||
仿照 11.7 中开发的 `Sorter` 接口,创建一个 `Miner` 接口并实现一些必要的操作。函数 `Min()` 接受一个 `Miner` 类型变量的集合,然后计算并返回集合中最小的元素。
|
仿照 11.7 中开发的 `Sorter` 接口,创建一个 `Miner` 接口并实现一些必要的操作。函数 `Min()` 接受一个 `Miner` 类型变量的集合,然后计算并返回集合中最小的元素。
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user