Go 学习笔记(3)流程控制

本文介绍了Go语言中的流程控制语句,包括if/else、switch和for循环的使用方式,以及特有的defer、panic和recover机制。通过示例展示了如何进行条件判断、循环操作以及异常恢复,强调了Go在错误处理上的独特之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Go 学习笔记(3)流程控制

1. 通用流程控制

if/else 条件语句

if/else 语句的基本格式为:

if cond1 {
    statement1
} else if cond2 {
    statement2
} else {
    statement3
}

在 Go 中,if/else 语句中条件不需要加小括号,而后面的执行语句需要加大括号。

if/else 后的条件可以有两种形式:

if cond {}
if define; cond {}

即在条件中可以可以执行其他语句或定义变量,但定义的变量只能在 if/else 语句体中使用:

if a := 1; a == 0 {
    statement1
} else if b := 2; a < 0 {
    fmt.Println(a)
    statement2
} else {
    fmt.Println(b)
    statement3
}
// a, b 不能在 if/else 外部使用
fmt.Println(a) // error
fmt.Println(b) // error

此外,Go 不支持三元运算符 ? :

switch 条件语句

switch 语句的基本格式为:

switch x {
case cond1, cond2, cond3:
    statement1
case cond4:
    statement2
default:
    statement3
}

每个 case 后可以有多个条件,用 , 隔开,若满足其中任意一个条件,则命中该 case。此外,case 中的条件不知可以为常量,也可以时表达式或函数的调用,只要结果类型相符即可。
如:

switch x {
case getX():
    statement1
case a + b:
    statement2
}

省略 switch 条件

还可以省略 switch 语句中的条件,但 case 中条件的类型需要为布尔值:

switch {
case cond1:
    statement1
case cond2:
    statement2
default:
    statement3
}

该用法可以与 if/else 语句相互替换:

if cond1 {
    statement1
} else if cond2 {
    statement2
} else {
    statement3
}

上述两种写法的效果完全相同,但 case 条件中不支持执行其他表达式,如下面语句无法编译:

switch {
case a := 1; a > 0: // error
    statement1
}

switch 后支持执行其他表达式:

// 带条件
switch a := 1; a {
case 1:
    statement1
case 2:
    statement2
}
// 或省略条件
switch a := 1; {
case a <= 1:
    statement1
case a > 1:
    statement2
}

fallthrough

默认情况下,只要命中一个 case,则整个 switch 语句会退出,可以通过添加 fallthrough 关键字继续执行下面的 case,即使该 case 的条件不会被命中:

a := 1
switch a {
case a == 1:
    fmt.Println("a == 1")
    fallthrough
case a > 1:
    fmt.Println("a > 1")
}
// 输出
// a == 1
// a > 1

for 循环语句

Go 中的 for 循环与 C 语言中的类似,只是可以省略小括号:

for expr1; cond; expr2 {

}

其中,expr1 为初始化语句,cond 为终止条件,expr2 为迭代后处理语句。
如:

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

“while” 循环

Go 中没有 while 关键字,while 循环也是使用 for 实现的,只需省略初始化语句和迭代处理语句即可:

i := 0
for i < 5 {
    fmt.Println(i)
    i++
}

break

for 循环可以不跟任何条件,构成无限循环,通过 break 退出循环:

i := 0
for {
    fmt.Println(i)
    i++
    if i == 5 {
        break
    }
}

continue

continue 用于跳过某次迭代,执行下次迭代:

i := 0
for i < 10 {
    if i % 3 == 0 {
        i++
        continue
    }
    fmt.Println(i)
    i++
}

2. 特殊流程控制

Go 中特有的流程控制语句:deferpanicrecover

defer 语句

defer语句可以推迟函数的运行,知道包含该defer的函数运行结束,才会执行 defer 指定的函数。

func main() {
    for i := 1; i < 5; i++ {
        defer fmt.Println(i)
    }
    fmt.Println("输出完成")
}
// 输出完成
// 4
// 3
// 2
// 1

保存 defer 延迟任务的是一个类似栈的后进先出的结构,因此后面 defer 的任务会先执行。
此外,从输出结果也可以看出来,defer 任务会在入栈时保存变量的副本,而不是实际函数调用时再捕获变量。

defer 一般用于关闭数据库及文件等资源。

panic 函数

panic 函数调用时会停止正常的程序流程,并执行被 defer 延迟的函数调用,随后输出错误日志,包括错误信息及对战追踪,最后程序停止运行。

// 来自 https://docs.microsoft.com/zh-cn/learn/modules/go-control-flow/4-use-defer-statement
package main

import "fmt"

func highlow(high int, low int) {
    if high < low {
        fmt.Println("Panic!")
        panic("highlow() low greater than high")
    }
    defer fmt.Println("Deferred: highlow(", high, ",", low, ")")
    fmt.Println("Call: highlow(", high, ",", low, ")")

    highlow(high, low + 1)
}

func main() {
    highlow(2, 0)
    fmt.Println("Program finished successfully!")
}

程序输出:

Call: highlow( 2 , 0 )
Call: highlow( 2 , 1 )
Call: highlow( 2 , 2 )
Panic!
Deferred: highlow( 2 , 2 )
Deferred: highlow( 2 , 1 )
Deferred: highlow( 2 , 0 )
panic: highlow() low greater than high

goroutine 1 [running]:
main.highlow(0x4b1580, 0xc00000e018)
	/tmp/sandbox543440378/prog.go:8 +0x285
main.highlow(0x2, 0x2)
	/tmp/sandbox543440378/prog.go:13 +0x20f
main.highlow(0x2, 0x1)
	/tmp/sandbox543440378/prog.go:13 +0x20f
main.highlow(0x2, 0x0)
	/tmp/sandbox543440378/prog.go:13 +0x20f
main.main()
	/tmp/sandbox543440378/prog.go:17 +0x25

可以看出,当 high=2, low=3时,程序调用了panic(),并在 panic 函数运行前执行了 defer 延迟的函数调用,最后输出 panic 的错误信息,随后程序便结束运行了,"Program finished successfully!" 并没有正常输出。

当发生数组越界或取消 nil 指针时,Go 程序也会自动的调用 panic 函数。

recover 函数

recover 函数用于避免程序的崩溃,可以从程序的崩溃中恢复,重新获得程序的控制权。

func main() {
    defer func() {
    handler := recover()
        if handler != nil {
            fmt.Println("main(): recover", handler)
        }
    }()

    highlow(2, 0)
    fmt.Println("Program finished successfully!")
}

main 函数中使用 recover 函数,则在 highlow 中程序发生崩溃时,仍是首先执行 defer 延迟的函数调用,但程序不会退出,而是执行 recover 函数中的内容。程序正常情况下,handlernil,不会产生印象,只有程序异常的情况下,handler 才不为 nil

Go 中的 panicrecover 机制类似于其他语言中的 try/catch,用于处理程序的异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值