# 3. Go语言流程控制

# 3.1 if 分支结构

Golang中,if 关键字用于条件判断,如果满足条件就做某事:

	score := 80
	if score > 90{
		fmt.Println("成绩优秀")
	}

如果存在第二个分支,则可以在上面代码的基础上添加 else 关键字以及另一代码块,这个代码块中的代码只有在条件不满足时才会执行,if 和 else 后的两个代码块是相互独立的分支,只能执行其中一个:

	score := 80
	if score >= 60 {
		fmt.Println("成绩及格")
	} else {
		fmt.Println("成绩不及格")
	}

如果存在第三个分支或者更多分支,则可以使用下面这种的形式:

	score := 80
	if score >= 60 && score < 70 {
		fmt.Println("成绩及格")
	} else if score >= 60 && score < 80 {
		fmt.Println("成绩良好")
	} else if score >= 80 && score <= 100 {
		fmt.Println("成绩优秀")
	} else {
		fmt.Println("成绩不及格")
	}

else if 分支的数量是没有限制的,但是为了代码的可读性,还是不要在 if 后面加入太多的 else if 结构,如果必须使用这种形式,则尽可能把先满足的条件放在前面。

总结起来 if else 基本语法如下:

if condition {
    // do something
} else if condition2 {
	// do something
} else if condition3 {
	//do something
} ... { 多个else if,再次忽略写法
	//do something
}else {
    // do something
}

还有一点,关键字 if 和 else 之后的左大括号{必须和关键字在同一行,如果你使用了 else if 结构,则前段代码块的右大括号}必须和 else if 关键字在同一行,这两条规则都是被编译器强制规定的。例如下面就是非法代码:

if x{
}
else { // 无效的
}

if 还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断,代码如下:

	if score := 80; score > 70 {
		fmt.Println("score > 70")
	}else{
		fmt.Println("score < 70")
	}

或者也可以根据一个函数的返回信息进行判断,示例如下:

if err := Connect(); err != nil {
    fmt.Println(err)
    return
}

Connect 是一个带有返回值的函数,err:=Connect() 是一个语句,执行 Connect 后,将错误保存到 err 变量中。err != nil 才是 if 的判断表达式,当 err 不为空时,打印错误并返回。这种写法可以将返回值与判断放在一行进行处理,而且返回值的作用范围被限制在 if、else 语句组合中。

# 3.2 for 循环结构

Go语言中的循环语句只支持 for 关键字,而不支持 while 和 do-while 结构。

Go语言的For循环有3中形式,只有其中的一种使用分号:

for init; condition; post { }
for condition { }
for { }
init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。

下面我们用例子给出这三种模式的代码:

	for x := 0; x < 10; x++ { //for init; condition; post{}模式
		fmt.Println(x)
	}

	i := 10
	for i > 0 { // 替代 while (i > 0) {}, 属于 for condition {} 模式
		fmt.Println(i)
		i--
	}

	j := 0
	for { //替代 while (true) {}, 属于 for {}模式
		j++
		if j > 10 {
			break
		}
	}

熟悉了Go语言的基本循环格式后,我们来用for循环实现一个九九乘法表的输出:

	for x := 1; x <= 9; x++ { //从1遍历到9
		for y := 1; y <= x; y++ { //乘法遍历
			fmt.Printf("%d*%d=%d ", x, y, x*y)
		}
		fmt.Println() //手动换行
	}

编译输出:

1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81

# 3.3 switch case 结构语句

Go语言中的 switch 结构使用上比其他语言更加灵活,表达式不需要为常量,甚至不需要为整数,case 按照从上到下的顺序进行求值,直到找到匹配的项,如果 switch 没有表达式,则对 true 进行匹配,因此,可以将 if else-if else 改写成一个 switch。

Go 编程语言中 switch 语句的语法如下:

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

变量 var1 可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式。 您可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3。

【示例】

	var a = "dog"
	switch a {
	case "dog":
		fmt.Println("wangwang")
	case "duck":
		fmt.Println("gaga")
	default:
		fmt.Println("...")
	}

	score := 90
	switch {
	case score >= 90:
		fmt.Println("A")
	case score >= 80:
		fmt.Println("B")
	case score >= 70:
		fmt.Println("C")
	case score >= 60:
		fmt.Println("D")
	default:
		fmt.Println("E")
	}

编译运行:

wangwang
A

在Go语言中 case 是一个独立的代码块,case执行完之后一般break,但可以使用 fallthrough 来强制执行下一个 case 代码块 代码如下:

	a := 2
	switch a {
	case 1:
		fmt.Println("a=1")
	case 2:
		fmt.Println("a=2")
		fallthrough
	case 3:
		fmt.Println("a=3")
	case 4:
		fmt.Println("a=4")
	default:
		fmt.Println("default")
	}

编译运行:

a=2
a=3

switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型:

	var x interface{}
	x = 22
	switch x.(type) {
	case int:
		fmt.Println("int")
	case int64:
		fmt.Println("int64")
	case float64:
		fmt.Println("float64")
	case bool:
		fmt.Println("bool")
	case string:
		fmt.Println("string")
	default:
		fmt.Printf("%T", x)
	}

编译运行:

int

# 3.4 goto break continue 语句

goto语句

goto 语句通过标签进行代码间的无条件跳转,同时 goto 语句在快速跳出循环、避免重复退出上也有一定的帮助,goto对应(标签)既可以定义在for循环前面,也可以定义在for循环后面,当跳转到标签地方时,继续执行标签下面的代码,示例:

	for a := 5; a > 0; a-- {
		fmt.Println(a)
		if a == 3 {
			goto loop
		}
	}
	fmt.Println("run here")
loop:
	fmt.Println("goto here")

编译执行:

5
4
3
goto here

break语句

break 语句可以结束 for、switch 和 select 的代码块,另外 break 语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的 for、switch 和 select 的代码块上。

	for a := 0; a < 5; a++ {
		for t := 0; t < 3; t++ {
			if t == 2 {
				break //跳出本层for循环
			}
			fmt.Println(a, t)
		}
	}

编译运行:

0 0
0 1
1 0
1 1
2 0
2 1
3 0
3 1
4 0
4 1

下面来演示下结合标签实现break跳出上一层for循环,示例:

OuterLoop:
	for i := 0; i < 2; i++ {
		for j := 0; j < 5; j++ {
			switch j {
			case 2:
				fmt.Println(i, j)
				break OuterLoop
			case 3:
				fmt.Println(i, j)
				break OuterLoop
			default:
				fmt.Println(i, j)
			}
		}
	}
	fmt.Println("here")

编译运行:

0 0
0 1
0 2
here

continue语句

continue 语句可以结束当前本次循环,开始下一次的循环迭代过程,仅限在 for 循环内使用, 示例:

	for a := 0; a < 5; a++ {
		for t := 0; t < 3; t++ {
			if t == 2 {
				continue //跳出本次for循环
			}
			fmt.Println(a, t)
		}
	}

编译运行:

0 0
0 1
1 0
1 1
2 0
2 1
3 0
3 1
4 0
4 1

在 continue 语句后添加标签时,表示开始标签对应的循环,例如:

OuterLoop:
	for i := 0; i < 3; i++ {
		for j := 0; j < 5; j++ {
			switch j {
			case 2:
				fmt.Println(i, j)
				continue OuterLoop
			}
		}
	}

代码输出结果如下:

0 2
1 2
2 2

最后对 goto break continue 做一个总结:

  • 三个语句都可以配合标签使用
  • 标签区分大小写,如果标签定义出来后,不使用将会报错
  • continue 单独使用是跳出本次循环;break单独使用是跳出本层循环
  • continue break配合标签使用可以用于多层循环跳出, break 配合标签主要跳出 最外层循环,而continue配合标签是跳出当次循环
  • goto配合标签主要是调整到执行位置,而continue break配合标签则是跳出循
最后更新时间: 3/2/2023, 4:55:04 PM