第七章 做猜数字游戏(for循环)
上次我们学习了条件分支,踏进编程门槛了。这次我们将学习如何重复处理同一件事。
7.1 重复
使用 for 可以编写重复(循环)处理。Go 的 for 语句有以下三种形式。
其他语言中的 while 和 foreach 的功能,也集中在 for 中。
最重要的,是记住的第一和第二条。第三点,目前只需在脑海的角落里留个印象。
for 条件 { ... }- 满足条件的情况下循环处理。相当于其他语言的while。for range 値 { ... }- 按顺序提取数组或切片等并循环。相当于其他语言中的foreach。for 初始化; 循环条件; 循环后处理 { ... }- 按“初期化、条件、循环后处理”的流程进行处理。
7.1.1 只有一个条件语句的 for 语句
首先介绍的,是在满足条件时重复的 for 语句。相当于其他语言中的 while 。
package main
import (
"fmt"
"math/rand/v2"
)
func main() {
for rand.N(2) == 1 {
fmt.Println("循环")
}
fmt.Println("结束")
}
$ go run .
循环
循环
循环
结束
如果 rand.N(2) 的返回值为 1,则执行 {} 的内容。
执行后再次执行 rand.N(2) ,检查返回值是否为 1,如果是,则执行 {} 的内容。
这样循环重复。如果不再满足条件,则退出 {} 并显示 结束 。运气好的话,此语句会循环很多次,但也可能直接结束。
这样在满足条件的情况下,重复执行 {} 里面的内容的语句就是 for 语句。
条件可以省略不写。在这种情况下,将始终被视为满足条件,形成所谓的“无限循环”。以下代码会输出大量文本,请准备好随时按“Ctrl+C”强制结束程序。
package main
import "fmt"
func main() {
for {
fmt.Println("无限循环")
}
}
7.1.2 用 range 指定循环范围
接下来介绍的是使用 range (范围)的 for 循环。
range 中还有不同的用法,这些将在后面介绍。本章节中首先介绍的是**“指定次数重复”的 range 用法**。
请看代码:
package main
import "fmt"
func main() {
for range 5 { // 执行5次
fmt.Println("循环")
}
fmt.Println("结束")
}
package main
import "fmt"
func main() {
var i = 0
for i = range 5 { // range 前面用等号的例子
fmt.Println(i)
}
fmt.Println("循环结束后会执行这里")
}
$ go run .
循环
循环
循环
循环
循环
结束
通过在 range 后面写上重复次数,就可以重复执行 {} 中的处理。
此外,您还可以将“重复几次”放入变量中使用。这可以通过在 range 前面写 := 或 = 语句来实现。
package main
import "fmt"
func main() {
for i := range 5 { // 用变量 i 当次数
fmt.Println(i)
}
fmt.Println("循环结束后会执行这里")
}
$ go run .
0
1
2
3
4
循环结束后会执行这里
请注意,此处 i 的起始值是 0 。
变量名可以随意起,但表示循环次数的值,通常会使用字母 i 。这个习惯,据说源自编程语言“APL”中使用的希腊字母 ι(伊奥塔)。
7.1.3 初期化・循环条件・循环后处理的用法
最后介绍的,是最经典的 for 循环用法。很多人可能在 C 语言中熟悉了这种写法。我们来写一段代码,像在 range 中那样重复执行 5 次。
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
$ go run .
0
1
2
3
4
以 初期化语句; 循环条件; 循环后处理 的形式,用英文分号 ; 分隔三个表达式。
这种情况下,这个 for 语句的意思是:
- 将变量
i初始化为 0, i小于 5 的时候重复循环- 每次循环将
i加 1(++是表示将 i 加 1 的符号)
如您所见,同样的功能,使用 range 可以更写得更短,感觉不会有人故意写得这么啰嗦。
但是,这个用 range 指定次数循环的功能,是最近才加入的。在此之前我们一直使用这种经典写法。为了阅读老代码,有必要了解这个语法。
7.2 循环控制
for 循环,可以在中途停止或跳过。
读到这里,感觉编程用的关键词变多了呢。
虽然可能会让你感到有些吃力,但这些关键词,并不需要一记住。
只需要在实践中多写几次,逐渐掌握即可!
7.2.1 break 中断
使用关键词 break ,可以在中途停止循环。
package main
import "fmt"
func main() {
for i := range 5 {
if i == 2 {
break
}
fmt.Println(i)
}
fmt.Println("循环后执行次语句")
}
$ go run .
0
1
循环后执行次语句
可以看到,range 指定执行5 次重复的循环,满足 if i == 2 这个条件时执行了 break ,在途中被中断。
7.2.2 continue 继续
使用 continue 语句,可以跳过本次循环的其余部分,继续下一次循环。
package main
import "fmt"
func main() {
for i := range 5 {
if i == 2 {
fmt.Println("跳过此次循环")
continue
}
fmt.Println(i) // 如果上面的continue执行了,这次将不会执行这一句
}
}
$ go run .
0
1
跳过此次循环
3
4
循环本身虽然被没有中断,但 continue 时,本该执行的 fmt.Println(i) 却在该次循环中被跳过。
您能理解发生了什么吗?
[面向有经验的人] 多重循环和带标签的 break、continue
break 和 continue ,通常只能中断或跳过最内层的循环。在多重嵌套的情况下,如果想要中断或继续外层循环,就需要与标签结合使用循环语句。
package main
import "fmt"
func main() {
loop: // "loop"标签
for i := range 3 {
for j := range 3 {
if i == 2 {
break loop // 指定标签,跳出特定循环的 break 语句
}
}
}
}
行头中写的 loop: ,可以为接下来的句子(在这种情况下是 for i := ... )添加标签。虽然 loop: 的额外缩进,可能会让你感到不适,但请适应。
学习 break 和 continue 等关键字时,作者本人也曾经觉得非常吃力。但在不断查阅资料与使用的过程中,逐渐就习惯了,所以不要着急,逐步推进吧。
7.3 输入
赶快用所学的知识,做一个猜数字游戏吧……
虽然我想这么说,但如果程序无法接收玩家输入,就没法做游戏。接受来自终端的输入的函数,只在本章用一次,所以我的介绍会比较简略。
在终端接收输入,可以使用 fmt.Scanln 。将变量的指针作为参数传给 fmt.Scanln , fmt.Scanln 就会将用户输入的值,赋值给该变量。
至于指针是什么,稍后会解释。
package main
import "fmt"
func main() {
fmt.Println("请输入数字")
input := 0
fmt.Scanln(&input) //加个 & ,将 input的指针传给fmt.Scanln
fmt.Println("你输入的值是", input)
}
$ go run .
请输入数字
(在这里输入数值,然后按回车键结束)
你输入的值是 42
7.4 制作猜数字游戏
前提知识准备好了。接下来我们制作一个猜数字游戏吧。
用程序生成一个随机的秘密值,玩家需要猜出这个值。如果猜错了,就继续猜,直到猜对为止。
同时作为提示,程序会显示“答案你比猜的数更大”或“答案你比猜的数更小”。
package main
import (
"fmt"
"math/rand/v2"
)
func main() {
answer := rand.N(100) // 生成 0 到 99 的数字
for {
fmt.Println("请输入数字")
input := 0
fmt.Scanln(&input)
if input == answer {
fmt.Println("答对了!")
break
} else if input < answer {
fmt.Println("答案你比猜的数更大")
} else {
fmt.Println("答案你比猜的数更小")
}
}
fmt.Println("游戏结束")
}
$ go run .
请输入数字
50
答案你比猜的数更大
请输入数字
75
答案你比猜的数更大
请输入数字
87
答案你比猜的数更小
请输入数字
81
答案你比猜的数更大
请输入数字
84
答案你比猜的数更大
请输入数字
86
答案你比猜的数更小
请输入数字
85
答对了!
游戏结束
综合运用学到的知识,我们已经能够制作猜数字游戏了。
能够使用 if 和 for 做东西,已经可以称得上是合格的程序员了。
如果心有余力,可以设定猜测次数限制,或统计玩家猜了几次,尝试各种玩法。
此外,这次做的是一个非常简单的数字猜测游戏,但不要小看这个猜数字游戏。
结合接下来将要说明的“数组・切片”结功能,这个游戏可以变成真正的推理游戏,就像“Hit and Blow”那样。
真正的游戏所需的精髓,你已经掌握不少了。
本章总结
- 使用
for可以编写循环处理。 for 条件 { ... }在条件满足的情况下重复循环。for range 回数 { ... }固定次数的循环。break,continue可以控制循环流程。