Logo
Section 1 / 10

if-else 语句

本节课详细讨论了 if-else 语句。

导入

if-else 语句

本节课详细讨论了 if-else 语句。

引言

到目前为止,我们已经了解到 Go 程序从 main() 函数开始执行,并按顺序逐条执行其中的语句。然而,我们常常希望仅在满足特定条件时才执行某些语句,这意味着需要在代码中做出判断。为此,Go 提供了以下条件或分支结构:

  • if-else 结构
  • switch-case 结构
  • select 结构

重复执行一个或多个语句(即完成某项任务)可以通过迭代或循环结构实现:

  • for(range)结构

此外,一些关键字如 break 和 continue 也可以改变循环的行为。还有 return 关键字用于退出语句块,以及 goto 关键字用于跳转到代码中的某个标签。

Go 完全省略了 if、switch 和 for 循环中条件周围的括号 ( 和 ),相比 Java、C++ 或 C#,这减少了视觉上的杂乱感。

if-else 结构

`if` 用于测试一个条件表达式。该表达式可以是逻辑型或布尔型。如果表达式求值为 `true`,则执行 `if` 后面大括号 `{}` 中的语句块;如果为 `false`,则跳过这些语句,直接执行 `if` 结构之后的语句。 ```go if condition { // 执行某些操作 } ```

...
if 结构

在第二种变体中,可以在 `if` 后添加一个 `else` 块,其内部包含用 `{}` 包裹的语句。当条件为 `false` 时,将执行 `else` 块中的内容。这意味着我们有两个互斥的分支,且只会执行其中一个: ```go if condition { // 执行某些操作 } else { // 执行其他操作 } ```

...
if 和 else 结构

在第三种变体中,可以在 `else` 之后再添加一个 `if` 条件,从而形成三个互斥的分支: ```go if condition1 { // 执行某些操作 } else if condition2 { // 执行其他操作 } else { // 通用捕获或默认情况 } ``` `else if` 分支的数量理论上没有限制,但从可读性考虑,不应过度使用。使用这种形式时,应将最可能为真的条件放在前面。

...
一个 else-if 与 if 和 else 的组合结构

大括号 {} 是强制性的,即使语句块中只有一条语句(尽管有些人不喜欢这一点,但这是统一且符合主流软件工程原则的做法)。if 和 else 后的大括号必须位于同一行。else if 和 else 关键字必须与前一部分结构的闭合大括号 } 在同一行。这两条规则对编译器来说都是强制性的。以下代码是无效的 Go 代码:

1if x { 2} 3else { // 无效 4}

注意:每个分支都应缩进 4(或 8)个空格或 1 个制表符,且闭合的大括号 } 应与 if 对齐。这一规范由 gofmt(Go 默认格式化工具)强制执行。条件表达式也可以是复合表达式,使用逻辑运算符 &&、|| 和 !,并可通过括号 () 显式指定优先级或提升可读性。

此外,条件周围的括号 () 并非必需。但在复杂条件中,使用括号有助于提高代码清晰度。一个典型应用场景是检测变量的不同取值,并根据情况执行不同的语句。

作为第一个示例,我们来判断一个整数是偶数还是奇数:

1package main 2import "fmt" 3 4func main() { 5 n := 42 6 // 使用 if 和 else 控制结构判断数字是否为偶数 7 if n % 2 == 0 { 8 fmt.Printf("该值是偶数\n") 9 } else { 10 fmt.Printf("该值是奇数\n") 11 } 12}

在上述代码中,我们在第 5 行声明了一个变量 n。由于一个数只能是偶数或奇数,因此我们采用 if-else 的第二种形式。第 7 行的条件 if n%2==0 仅在 n 为偶数时为真。若条件为真,则输出“该值是偶数”;否则,控制流跳过第 8 行,进入 else 块,执行第 10 行,输出“该值是奇数”。

if 后的条件表达式是一个布尔表达式,但它也可以直接是一个布尔值,如下例所示:

1package main 2import "fmt" 3 4func main() { 5 bool1 := true 6 // 条件本身就是一个布尔值 7 if bool1 { 8 fmt.Printf("该值为真\n") 9 } else { 10 fmt.Printf("该值为假\n") 11 } 12}

在上述代码中,我们在第 5 行声明并初始化了一个布尔变量 bool1 为 true。第 7 行的条件 if bool1 不需要写成 if bool1 == true,因为 bool1 本身已经是布尔类型。对于这个程序,控制流总是进入 if 块,屏幕上将输出“该值为真”。

对于特殊情况,你也可以这样写:

1if true { 2 fmt.Printf("我始终会执行这个分支"); 3}

此时大括号内的代码块总会被执行,因此这种写法意义不大。

反过来,也可以这样写:

1if false { 2 fmt.Printf("我永远不会执行这段代码!") 3}

此时大括号内的代码块将永远不会被执行。通常建议测试为真或正向条件,但也可以通过 !(非)操作符测试相反的情况:

1if !bool1 // 或 if !(condition)

在最后一种情况下,括号 () 通常是必要的,例如:

1if !(var1 == var2)

这可以简化为更短的形式:

1if var1 != var2

在 Go 代码中,有一种常见写法:当 if 语句以 break、continue、goto 或 return 结束时,省略 else 子句。例如,当需要返回一个偶数值时,可以这样写:

1if n % 2 == 0 { 2 return n 3} 4fmt.Printf("继续处理奇数值\n")

当根据条件返回不同值 x 或 y 时,应使用如下模式:

1if condition { 2 return x 3} 4return y

举个例子:

1if val > max { 2 return val // 返回 val 作为最大值 3} 4return max // 返回 max 作为最大值

if 结构还可以以一个初始化语句开头(即在声明变量的同时赋值)。其语法形式如下(初始化后的分号 ; 必须存在):

1if initialization; condition { 2 // 执行某些操作 3}

例如,与其写成:

1val := 10 2if val > max { 3 // 执行某些操作 4}

不如写成:

1if val := 10; val > max { 2 // 执行某些操作 3}

但请注意,变量 val 仅在 if、else if 和 else 块内部有效。如果尝试在程序其他地方访问 val,编译器将报错:“undefined: val”。这种在 if 语句中进行初始化的方式可以进一步发挥用途,如下代码所示:

1if value := process(data); value > max { 2 ... 3}

可以在 if 中获取函数 process() 的返回结果,并根据 value 的值采取相应行动。

以下是使用 if 结构多种变体的完整示例:

1package main 2import "fmt" 3 4func main() { 5 var first int = 10 6 var cond int 7 if first <= 0 { 8 fmt.Printf("first 小于或等于 0\n") 9 } else if first > 0 && first < 5 { 10 fmt.Printf("first 在 0 和 5 之间\n") 11 } else { 12 fmt.Printf("first 大于等于 5\n") 13 } 14 if cond = 5; cond > 10 { 15 fmt.Printf("cond 大于 10\n") 16 } else { 17 fmt.Printf("cond 不大于 10\n") 18 } 19}

在上述代码中,我们声明了两个整型变量 first 和 cond。第 7 行的条件 if first <= 0 若为真,则执行第 8 行,然后控制流跳至第 14 行。

若为假,则控制流从第 7 行直接跳至第 9 行。此处使用 else if,条件为 first > 0 && first < 5。若该条件为真,则控制流跳至第 10 行,再直接跳至第 14 行。否则,控制流从第 9 行直接跳至第 11 行。

第 11 行是 else 块。在 else 块中,第 12 行被执行。执行完 else 块中的语句后,控制流到达第 14 行。若第 14 行的条件为真,则执行第 15 行;否则执行第 17 行的 else 块。

观察第 14 行的条件:if cond = 5; cond > 10。这里在条件判断时同时完成了 cond 的初始化。

下图展示了上述程序中控制流的转移过程。


以上就是关于 if-else 结构如何控制流程的全部内容。下一课将介绍如何检测内置函数的错误。

基本结构与基础数据类型

函数中的错误检测