4、流程控制语句

分支语句

if...else

if condition1 {
    // do something
} else if condition2 {
    // do something else
} else {
    // catch-all or default
}

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

带初始化语句的 if

例如Connect() 是一个带有返回值的函数,err := Connect() 是一个语句,执行 Connect() 后,将错误保存到 err 变量中。

err != nil 才是 if 的判断表达式,当 err 不为空时,打印错误并返回。

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

switch...case

Go语言改进了 switch 的语法设计,case 与 case 之间是独立的代码块,不需要通过 break 语句跳出当前 case 代码块以避免执行到下一行

var a = "hello"
switch a {
case "hello":
    fmt.Println(1)
case "world":
    fmt.Println(2)
default:
    fmt.Println(0)
}

一分支多值

var a = "mum"
switch a {
case "mum", "daddy":
    fmt.Println("family")
}

分支表达式

var r int = 11
switch {
case r > 10 && r < 20:
    fmt.Println(r)
}

fallthrough

fallthrough可以实现穿透的效果,从当前case块穿透到下一个case并执行,一次只能穿透一层

**注意:**使用fallthrough时,将无条件执行下一个case,而不检查其条件。

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

/*
 1
 2
*/

带初始化语句的switch

switch 初始化语句; 表达式 {
case 值1:
    // ...
}

type switch类型选择

Go的switch有一个特殊形式,用于判断变量的具体类型:

switch x.(type) {
case 类型1:
    // x是类型1
case 类型2:
    // x是类型2
default:
    // 其他类型
}

这被称为type switch,是Go处理多态的重要方式之一:

func describe(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("整数: %d\n", v)
    case string:
        fmt.Printf("字符串: %s (长度: %d)\n", v, len(v))
    case bool:
        fmt.Printf("布尔值: %t\n", v)
    case nil:
        fmt.Println("nil值")
    default:
        fmt.Printf("其他类型: %T\n", v)
    }
}

func main() {
    describe(42)
    describe("Hello World!")
    describe(true)
    describe(nil)
    describe(3.14)
}

循环语句

for

Go语言中的循环语句只支持 for 关键字,而不支持 while 和 do-while 结构,关键字 for 的基本使用方法与C/C++非常接近

sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

注意:左花括号{必须与 for 处于同一行。

无限循环

for{
    fmt.Println("hello")
}

continue 和 break

Go语言的 for 循环同样支持 continue 和 break 来控制循环,同时可以使用标签(label)来精确控制多层循环中的跳转

JLoop:
for j := 0; j < 5; j++ {
    for i := 0; i < 10; i++ {
        if i > 5 {
            break JLoop
        }
        fmt.Println(i)
    }
}

只有循环条件

var i int
for i <= 10 {
    i++
}

for-range循环

for-range是Go中遍历数组、切片、映射、通道等内置集合的惯用方式:

for 索引, 值 := range 集合 {
    // 使用索引和值
}
// 遍历切片
func processItems(items []string) {
    for i, item := range items {
        fmt.Printf("索引 %d: %s\n", i, item)
    }
}

// 遍历映射
func displayMap(data map[string]int) {
    for key, value := range data {
        fmt.Printf("%s: %d\n", key, value)
    }
}

// 只需要索引
func processIndices(items []string) {
    for i := range items {
        fmt.Printf("处理索引 %d\n", i)
    }
}

// 只需要值
func processValues(items []string) {
    for _, item := range items {
        fmt.Println(item)
    }
}

在 Go 1.22.0 中支持对整数进行 range

func main() {
	for i := range 5 {
		fmt.Println(i)
	}
}
/*
0
1
2
3
4
*/

goto

Go语言中 goto 语句通过标签进行代码间的无条件跳转,同时 goto 语句在快速跳出循环、避免重复退出上也有一定的帮助,使用 goto 语句能简化一些代码的实现过程。

goto只能跳转到同一函数内的标签,不能跳过变量声明,也不能跳入内部作用域。

跳出循环

package main

import (
	"fmt"
)

func main() {
	i := 0
	for {
		i++
		fmt.Println(i)
		if i == 5 {
			goto myFlag
		}
	}

myFlag:
	fmt.Println("done")
}