上一篇:
下一篇:
Go 的控制结构与C 的控制结构相关,但在一些重要方面有所不同
do
和 while
循环,只有稍微泛化的 for
循环;切换更加灵活if
和 switch
接受一个可选的初始化语句,类似于for
break
和 continue
语句接受一个可选的标签,用于标识 break
跳出位置和 continue
转到继续执行的位置switch obj.(type)
和多路通信复用器 select
。这两个控制结构分别在 [[200-编程语言/Go/基础/反射|反射]] 中介绍 switch obj.(type)
和 [[Channels]] 中介绍它们的语法也略有不同;没有括号,并且 主体必须总是用大括号分隔
在 Go 中,有如下条件控制语句
if
语句:如果一个条件为true
,则执行一些代码if-else
语句:如果条件为 true
,执行一些代码,如果条件为 false
,执行另一段代码if-else if-else
语句:为两个以上的条件执行不同的代码switch....case
语句:选择要执行的众多代码块中的一个if
语句if
语句仅在指定的条件求值为 true
时执行代码块
if condition {
// condition 为 true 时执行的代码
}
如果x
为 true
,下面的例子将输出 "Japan"
:
package main
import "fmt"
func main() {
var s = "Japan"
x := true
if x {
fmt.Println(s)
}
}
if-else
语句if....else
语句允许您在指定条件为 true
时执行一个代码块,在指定条件为 false
时执行另一个代码块
if condition {
// condition 为 true 时执行的代码
} else {
// condition 为 false 时执行的代码
}
[!ERROR] 注意
}
后面放else {
也是强制性的,如果不这样做,也将抛出syntax
错误
如果 x
为 100
,下面的示例将输出 "Japan"
,否则输出 Canada
package main
import "fmt"
func main() {
x := 100
if x == 100 {
fmt.Println("Japan")
} else {
fmt.Println("Canada")
}
}
if-else if-else
语句if...else if...else
语句是多个 if...else
语句的嵌套
if condition-1 {
// 如果condition-1 为 true,将执行的代码
} else if condition-2 {
// 如果condition-2 为 true,将执行的代码
} else {
// 如果condition-1 和condition-2 均为 false,将执行的代码
}
如果 x
为 100
,下面的示例将输出 "Japan"
。如果 x
为 50
,将输出 Germany
其他情况将输出 Canada
package main
import (
"fmt"
)
func main() {
x := 100
if x == 50 {
fmt.Println("Germany")
} else if x == 100 {
fmt.Println("Japan")
} else {
fmt.Println("Canada")
}
}
if
语句初始化if
语句支持复合语法,在这种语法中,被测试的表达式前面有一个初始化语句
if var declaration; condition {
// condition 为 true 时执行的代码
}
如果 x
是 100
,下面的例子将输出"Germany"
:
package main
import (
"fmt"
)
func main() {
if x := 100; x == 100 {
fmt.Println("Germany")
}
}
x
只能在 if
语句组中使用,离开 if
语句组,就无法在使用了switch
语句switch
语句用于 从多个代码块中选择一个执行。它的完整语法如下
switch initializer; expr {
case value1:
<statement-1>
<....>
<statement-n>
case value2:
<statement-1>
<....>
<statement-n>
....
default:
<statement-1>
<....>
<statement-n>
}
initializer
是一个简单的初始化语句,可以省略expr
是一个表达式,value
的值的类型必须与 expr
表达式的类型相同[!ERROR] 错误
所有的
case
值都应该与switch
后的表达式的值的类型相同,否则将抛出错误
- 不像 C 那样要求
expr
必须是整数
考虑以下示例,它在特定日期显示不同的消息
package main
import (
"fmt"
"time")
func main() {
today := time.Now()
switch /*初始化语句;*/ today.Day() {
case 5:
fmt.Println("Today is 5th. Clean your house.")
case 10:
fmt.Println("Today is 10th. Buy some wine.")
case 15:
fmt.Println("Today is 15th. Visit a doctor.")
case 25:
fmt.Println("Today is 25th. Buy some food.")
case 31:
fmt.Println("Party tonight.")
default:
fmt.Println("No information available for that day.")
}
}
case
项,则会执行 default
语句cases
的 switch
带有多 case
行语句的 switch
用于为许多类似情况选择共同的代码块
package main
import (
"fmt"
"time"
)
func main() {
today := time.Now()
var t int = today.Day()
switch /*初始化语句;*/ t {
case 5, 10, 15:
fmt.Println("Clean your house.")
case 25, 26, 27:
fmt.Println("Buy some food.")
case 31:
fmt.Println("Party tonight.")
default:
fmt.Println("No information available for that day.")
}
}
fallthrough case
的 switch
fallthrough
关键字用于 强制控制通过连续的 case
块
package main
import (
"fmt"
"time"
)
func main() {
today := time.Now()
switch /*初始化语句;*/ today.Day() {
case 5:
fmt.Println("Clean your house.")
fallthrough // 强制控制流转到下一个 case 语句组
case 10:
fmt.Println("Buy some wine.")
fallthrough //强制控制流转到下一个 case 语句组
case 15:
fmt.Println("Visit a doctor.")
fallthrough // 强制控制流转到下一个 case 语句组
case 25:
fmt.Println("Buy some food.")
fallthrough // 强制控制流转到下一个 case 语句组
case 31:
fmt.Println("Party tonight.")
default:
fmt.Println("No information available for that day.")
}
}
case
的 swith
case
语句也可以与比较运算符和逻辑运算符一起使用
package main
import (
"fmt"
"time"
)
func main() {
today := time.Now()
switch /*初始化语句;*/ { // 此处没有表达式
case today.Day() < 5: // case 一个条件
fmt.Println("Clean your house.")
case today.Day() <= 10: // case 一个条件
fmt.Println("Buy some wine.")
case today.Day() > 15: // case 一个条件
fmt.Println("Visit a doctor.")
case today.Day() == 25: // case 一个条件
fmt.Println("Buy some food.")
default:
fmt.Println("No information available for that day.")
}
}
switch
初始化switch
关键字后面可以紧接一个简单的初始化语句,其中可以声明和初始化 switch
代码块中的局部变量
package main
import (
"fmt"
"time"
)
func main() {
switch today := time.Now(); /*expr*/{
case today.Day() < 5:
fmt.Println("Clean your house.")
case today.Day() <= 10:
fmt.Println("Buy some wine.")
case today.Day() > 15:
fmt.Println("Visit a doctor.")
case today.Day() == 25:
fmt.Println("Buy some food.")
default:
fmt.Println("No information available for that day.")
}
}
Go 只有一个循环语句,即 for
语句。基本的 for
循环结构如下
for init; condition; post {
// 循环体执行的代码
}
init
是循环的初始化,只在进入循环时执行一次condition
是条件表达式
condition
为 true
时,执行 for
中的代码condition
为 false
时,结束循环post
在每次迭代结束时执行,通常用于改变循环条件init
语句通常是一个简短的变量声明,在那里声明的变量仅在 for
语句的作用域内可见。一旦condition
条件表达式的计算结果为 false
,循环将停止迭代
[!WARNING] 注意
for
的init; condition; post
没有被()
包围,{}
是必须的,且{
必须和for
在同一行
例如,计算 1 ∼ 100 1 \sim 100 1∼100 的和
package main
import "fmt"
func main() {
// 基本结构
sum := 0
for j := 1; j <= 100; j++ {
sum += j
}
fmt.Println(sum)
}
init
和 post
语句是可选的,它类似于 C 的 while
循环。在这一点上,你可以 去掉分号
for condition {} // 类似 C 的 while
例如,计算 1 ∼ 100 1 \sim 100 1∼100 的和
package main
import "fmt"
func main() {
// 省略 init 和 post 此时,类似 C 的 while,这样就可以省略两边的分号
sum := 0
i := 1
for i <= 100 {
sum += i
i++
}
fmt.Println(sum)
}
如果省略循环条件,则它将永远循环,因此可以紧凑地表示无限循环。
for {} // 类似于 C 的 for(;;)
如果 inti, condition, post
只省略其中之一,那么分号(;
) 将不能省略
i := 0
for ; i < 10; i++ {
// 条件
}
for
练习package main
import "fmt"
func main() {
/* 找出 100 以内的奇数 */ fmt.Print("Even number: ")
for i := 0; i < 100; i++ {
if i%2 != 0 {
fmt.Print(i)
}
fmt.Print(" ")
}
}
一个三位数的各位上的数的立方和等于该数本身则为水仙花数
package main
import (
"fmt"
)
func main() {
/* 一个三位数的各位上的数的立方和等于该数本身则为水仙花数:找出 100 ~ 999 内的所有水仙花数 */
fmt.Print("daffodil number: ")
for number := 100; number < 1000; number++ {
hundred := number / 100 // 百位上的数字
ten := number % 100 / 10 // 十位上的数字
one := number % 10
if hundred*hundred*hundred+ten*ten*ten+one*one*one == number {
fmt.Print(number)
fmt.Print(" ")
}
}
}
package main
import (
"fmt"
)
func main() {
/* 1 ~ 100 含有 7 或是 7 的倍数的数 */
fmt.Print("含有 7 或者 是 7 的倍数的数: ")
for number := 7; number < 100; number++ {
/* 7 的倍数 十位是 7 个位是 7 */
if number%7 == 0 || number/10 == 7 || number%10 == 7 {
fmt.Print(number)
fmt.Print(" ")
}
}
}
range
关键字关键 range
字用于更轻松地迭代数 数组、切片、字符串、map 及 通道(channel)
[!NOTE] 注意
数组,切片,map 马上就会涉及,但是通道将在go coroutine
部分介绍
使用 range
关键字的方式如下
for index, value := array|slice|map {
// 每次迭代执行的代码
}
鉴于我们只学习了 string
,现在我们使用 range
关键字来遍历 string
类型的值
package main
import "fmt"
func main() {
str := "你好, 小爱同学"
for i, v := range str {
//fmt.Printf("i type: %T, v type: %T\n", i, v) // v 的类型是 int32 这是由于 Go 使用 Unicode 处理字符串使用
fmt.Println(i, string(v))
}
}
Go 1.22 版本新增了 range
对整数的支持
for i := range 5 {
fmt.Println(i) // 0 1 2 3 4
}
for range 3 {
fmt.Println("hello") // 输出 3 次 hello
}
continue
关键字该 continue
语句用于跳过循环中的一个或多个迭代。然后,它继续进行循环中的下一次迭代
package main
import "fmt"
func main() {
for i:=0; i < 10; i++ {
if i % 2 != 0 {
continue
}
fmt.Printf("%d ", i)
}
}
continue
语句后可以添加标签,表示开始标签对应的循环
package main
import "fmt"
func main() {
forloop1:
for i := 0; i < 5; i++ {
//forloop2:
for j := 0; j < 5; j++ {
if i == 2 || j == 2 {
continue forloop1
}
fmt.Printf("%v-%v\n", i, j)
}
}
}
break
关键字该 break
语句用于 中断/终止循环执行。
package main
import "fmt"
func main() {
for i:=0; i < 10; i++ {
fmt.Printf("%d ", i)
if i == 5 {
break // 跳出本层循环
}
}
fmt.Printf("\n")
}
break
语句还可以在语句后面添加 标签,表示 退出某个标签对应的代码块
package main
import "fmt"
func main() {
BREAKDEMO1:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
break BREAKDEMO1 // 跳出标签指定的语句
}
fmt.Printf("%v-%v\n", i, j)
}
}
fmt.Println("...")
}
break
关键字还可以用于switch
和select
的代码块上
for
可以将一个循环放在另一个循环中。处于另一个循环内部的循环称为 “内部循环”。在这里,“外部循环” 的每迭代执行一次,“内部循环” 将完整执行:
示例:寻找 2 ∼ 100 2 \sim 100 2∼100 内的素数
package main
import "fmt"
func main() {
/* 寻找 2 ~ 100 内的素数 */
for num := 2; num < 100; num++ {
var j int = 2
for ; j < num; j++ {
if num%j == 0 {
fmt.Printf("%d is not a prime.\n", num)
break // 跳出内层循环
}
}
if j == num {
fmt.Printf("%d is a prime.\n", num)
}
}
}
goto
关键字goto
语句通过标签进行代码间的 无条件跳转。goto
语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go 语言中使用 goto
语句能简化一些代码的实现过程。 例如双层嵌套的 for
循环要退出时
func f() {
a := 0
if a == 1 {
goto LABEL1
} else {
fmt.Println("other")
}
LABEL1:
fmt.Printf("next...")
}
func main() {
f()
}
func f() {
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
if i == 2 && j == 2 {
goto LABEL1
}
}
}
LABEL1:
fmt.Println("label1")
}
func main() {
f()
}
package main
import "fmt"
func main() {
var num int
fmt.Printf("请输入一个整数: ")
fmt.Scanf("%d", &num)
if num%2 == 0 {
fmt.Printf("%d 是偶数\n", num)
} else {
fmt.Printf("%d 是奇数\n", num)
}
}
package main
import "fmt"
func main2() {
sum := 0
for i := 3; i < 100; i++ {
if i%3 != 0 {
continue
}
sum += i
}
fmt.Printf("1 到 100 中能被 3 整数的数字之和为: %d\n", sum)
}
package main
import "fmt"
func main() {
for i := 1; i < 10; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d * %d = %-5d", i, j, i*j)
}
fmt.Println()
}
fmt.Println()
for i := 9; i > 0; i-- {
for j := 1; j <= i; j++ {
fmt.Printf("%d * %d = %-5d", i, j, i*j)
}
fmt.Println()
}
}
package main
import (
"fmt"
"math"
)
func main() {
var num int
fmt.Scan(&num)
var i int
for i = 2; i < int(math.Sqrt(float64(num))); i++ {
if num%i == 0 {
break
}
}
if i < int(math.Sqrt(float64(num))) {
fmt.Printf("%d 不是一个素数\n", num)
} else {
fmt.Printf("%d 是一个素数\n", num)
}
}
package main
import "fmt"
func main() {
var str string
fmt.Printf("输入一个字符串: ")
fmt.Scan(&str)
// var i, j = 0, len(str) - 1 len 返回的不是字符数而是字节数
rune_string := []rune(str)
i, j := 0, len(rune_string)-1
for i != j {
if rune_string[i] != rune_string[j] {
break
}
i++
j--
}
if i == j {
fmt.Printf("%s 是一个回文串\n", str)
} else {
fmt.Printf("%s 不是一个回文串\n", str)
}
}
package main
import "fmt"
func main() {
var num int
fmt.Printf("输入一个数: ")
fmt.Scan(&num)
fac := 1
for i := 1; i <= num; i++ {
fac *= i
}
fmt.Printf("%d 的阶乘为: %d\n", num, fac)
}
计算并输出斐波拉契数列的第 n n n 项
package main
import "fmt"
func main() {
var num int
fmt.Printf("输入整数: ")
fmt.Scan(&num)
a, b := 0, 1
for num > 0 {
a, b = b, a+b
num--
}
fmt.Printf("第 %d 项斐波拉契数列为: %d\n", num, a)
}
本节我们介绍了 Go 中的控制结构。