Files
the-way-to-go_ZH_CN/eBook/05.4.md
Unknown f8550edc9a 5.4.3
2014-06-06 14:17:29 -04:00

257 lines
8.0 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 啊哦,亲,你看得也太快了。。。还没翻译完呢 0 0
要不等到 **2014 年 6 月 8 日** 再来看看吧~~
这里还有一些其它的学习资源噢~
- [《Go编程基础》](https://github.com/Unknwon/go-fundamental-programming)
- [《Go Web编程》](https://github.com/astaxie/build-web-application-with-golang)
- [《Go名库讲解》](https://github.com/Unknwon/go-rock-libraries-showcases)
神马?你说你不想学习?那好吧,去逛逛看看行情也行~
- [Go Walker](https://gowalker.org) **Go 项目 API 文档在线浏览工具**
- [Go 中国社区](http://bbs.go-china.org)
- [Go语言学习园地](http://studygolang.com/)
- [Golang中国](http://golangtc.com)
# 5.4 for 结构
如果想要重复执行某些语句Go 语言中您只有 for 结构可以使用。不要小看它,这个 for 结构比其它语言中的更为灵活。
**注意事项** 其它许多语言中也没有发现和 do while 完全对等的 for 结构,可能是因为这种需求并不是那么强烈。
## 5.4.1 基于计数器的迭代
文件 for1.go 中演示了最简单的基于计数器的迭代,基本形式为:
for 初始化语句; 条件语句; 修饰语句 {}
Listing 5.6 [for1.go](examples/chapter_5/for1.go)
```
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Printf("This is the %d iteration\n", i)
}
}
```
输出:
```
This is the 0 iteration
This is the 1 iteration
This is the 2 iteration
This is the 3 iteration
This is the 4 iteration
```
由花括号括起来的代码块会被重复执行已知次数,该次数是根据计数器(此例为 i决定的。循环开始前会执行且仅会执行一次初始化语句 `i := 0;`;这比在循环之前声明更为简短。紧接着的是条件语句 `i < 5;`,在每次循环开始前都会进行判断,一旦判断结果为 false则退出循环体。最后一部分为修饰语句 `i++`,一般用于增加或减少计数器。
这三部分组成的循环的头部,它们之间使用分号 `;` 相隔,但并不需要括号 `()` 将它们括起来。例如:`for (i = 0; i < 10; i++) { }`,这是无效的代码!
同样的,左花括号 `{` 必须和 for 语句在同一行,计数器的生命周期在遇到右花括号 `}` 时便终止。一般习惯使用 i、j、z 或 ix 等较短的名称命名计数器。
特别注意,永远不要在循环体内修改计数器,这在任何语言中都是非常差的实践!
**练习 5.3** 文件 [i_undefined.go](exercises/chapter_5/i_undefined.go) 无法编译,请解释原因。
```
package main
import (
"fmt"
)
func main() {
var i int
for i=0; i<10; i++ {
fmt.Printf("%v\n", i)
}
fmt.Printf("%v\n", i) //<-- compile error: undefined i
}
```
如果才能使得程序通过编译?
您还可以在循环中同时使用多个计数器:
for i, j := 0, N; i < j; i, j = i+1, j-1 {}
这得益于 Go 语言具有的平行赋值的特性可以查看第 7 string_reverse.go 中反转数组的示例)。
您可以将两个 for 循环嵌套起来
```
for i:=0; i<5; ji++ {
for j:=0; j<10; j++ {
println(j)
}
}
```
如果您使用 for 循环迭代一个 Unicode 编码的字符串会发生什么
Listing 5.7 [for_string.go](examples/chapter_5/for_string.go)
```
package main
import "fmt"
func main() {
str := "Go is a beautiful language!"
fmt.Printf("The length of str is: %d\n", len(str))
for ix :=0; ix < len(str); ix++ {
fmt.Printf("Character on position %d is: %c \n", ix, str[ix])
}
str2 := "日本語"
fmt.Printf("The length of str2 is: %d\n", len(str2))
for ix :=0; ix < len(str2); ix++ {
fmt.Printf("Character on position %d is: %c \n", ix, str2[ix])
}
}
```
输出
```
The length of str is: 27
Character on position 0 is: G
Character on position 1 is: o
Character on position 2 is:
Character on position 3 is: i
Character on position 4 is: s
Character on position 5 is:
Character on position 6 is: a
Character on position 7 is:
Character on position 8 is: b
Character on position 9 is: e
Character on position 10 is: a
Character on position 11 is: u
Character on position 12 is: t
Character on position 13 is: i
Character on position 14 is: f
Character on position 15 is: u
Character on position 16 is: l
Character on position 17 is:
Character on position 18 is: l
Character on position 19 is: a
Character on position 20 is: n
Character on position 21 is: g
Character on position 22 is: u
Character on position 23 is: a
Character on position 24 is: g
Character on position 25 is: e
Character on position 26 is: !
The length of str2 is: 9
Character on position 0 is: æ
Character on position 1 is: —
Character on position 2 is: ¥
Character on position 3 is: æ
Character on position 4 is: œ
Character on position 5 is: ¬
Character on position 6 is: è
Character on position 7 is: ª
Character on position 8 is: ž
```
如果我们打印 str str2 的长度会分别得到 27 9
由此我们可以发现ASCII 编码的字符占用 1 个字节既每个索引都指向不同的字符而非 ASCII 编码的字符占有 2 4 个字节不能单纯地使用索引来判断是否为同一个字符我们会在第 5.4.4 节解决这个问题
### 练习题
**练习 5.4** [for_loop.go](exercises/chapter_5/for_loop.go)
1. 使用 for 结构创建一个简单的循环要求循环 15 次然后使用 fmt 包来打印计数器的值
2. 使用 goto 语句重写循环要求不能使用 for 关键字
**练习 5.5** [for_character.go](exercises/chapter_5/for_character.go)
创建一个程序要求能够打印类似下面的结果直到每行 25 个字符时为止
```
G
GG
GGG
GGGG
GGGGG
GGGGGG
```
1. 使用 2 层嵌套 for 循环
2. 使用一层 for 循环以及字符串截断
**练习 5.6** [bitwise_complement.go](exercises/chapter_5/bitwise_complement.go)
使用按位补码从 0 10使用位表达式 `%b` 来格式化输出
**练习 5.7** Fizz-Buzz 问题[fizzbuzz.go](exercises/chapter_5/fizzbuzz.go)
写一个从 1 打印到 100 的程序但是每当遇到 3 的倍数时不打印相应的数字但打印一次 "Fizz"。遇到 5 的倍数时打印 `Buzz` 而不是相应的数字对于同时为 3 5 的倍数的数打印 `FizzBuzz`提示使用 switch 语句)。
**练习 5.8** Fizz-Buzz 问题[rectangle_stars.go](exercises/chapter_5/rectangle_stars.go)
使用 `*` 符号打印宽为 20高为 10 的矩形
## 5.4.2 基于条件判断的迭代
for 结构的第二种形式是没有头部的条件判断迭代类似其它语言中的 while 循环基本形式为`for 条件语句 {}`
您也可以认为这是没有初始化语句和修饰语句的 for 结构因此 `;;` 便是多余的了
Listing 5.8 [for2.go](examples/chapter_5/for2.go)
```
package main
import "fmt"
func main() {
var i int = 5
for i >= 0 {
i = i - 1
fmt.Printf("The variable i is now: %d\n", i)
}
}
```
输出
```
The variable i is now: 4
The variable i is now: 3
The variable i is now: 2
The variable i is now: 1
The variable i is now: 0
The variable i is now: -1
```
## 5.4.3 无限循环
条件语句是可以被省略的 `i:=0; ; i++` `for { }` `for ;; { }``;;` 会在使用 gofmt 时被移除这些循环的本质就是无限循环最后一个形式也可以被改写为 `for true { }`但一般情况下都会直接写 `for { }`
如果 for 循环的头部没有条件语句那么就会认为条件永远为 true因此循环体内必须有相关的条件判断以确保会在某个时刻退出循环
想要直接退出循环体可以使用 break 语句 5.5 return 语句直接返回 6.1 )。
但这两者之间有所区别break 只是退出当前的循环体 return 语句提前对函数进行返回不会执行后续的代码
无限循环的经典应用是服务器用于不断等待和接受新的请求
```
for t, err = p.Token(); err == nil; t, err = p.Token() {
...
}
```
## 5.4.4 for-range 结构