「学习笔记」Golang – 控制语句与错误处理
文章目录
Golang中的条件控制语句省去了许多不必要的附加符号,使代码更加简洁。
for 循环
Golang只有一种循环结构:for循环,基本形式为:
for 初始化语句; 条件语句; 修饰语句 {}
- 基本的
for循环由三部分组成,它们用分号隔开:- 初始化语句(可选):在第一次迭代前执行
- 条件表达式:在每次迭代前求值
- 后置语句(可选):在每次迭代的结尾执行
- 与其他语言不同,
Golang的for语句后面的三个构成部分外没有小括号,大括号{}则是必须的。
// for 没有小括号
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// for 初始化语句和后置语句是可选的。
var j int = 0
for j < 10 {
fmt.Println(j)
j++
}
// 如果省略循环条件,则无限循环
for {
fmt.Println("Running...")
time.Sleep(time.Millisecond * 500)
}
- 循环控制语句可以控制循环体内语句的执行过程:
break语句:经常用于中断当前for循环或跳出switch语句。continue语句:跳过当前循环的剩余语句,然后继续进行下一轮循环。goto语句:将控制转移到被标记的语句。
for-range 遍历
数组、string、slice、map、channel等都可以使用for-range语句遍历。
slice := []int{1, 2, 3, 4, 5}
for key, value := range slice {
fmt.Println(key, value)
}
// channel 没有 key 且阻塞
channel := make(chan int, 10)
for value := range channel {
fmt.Println(value)
}
if 判断
Golang的if判断语句与for循环类似,表达式外无需小括号,而大括号{}则是必须的。
if condition1 {
// do something
} else if condition2 {
// do something else
} else {
// default
}
和for一样,if语句可以在条件表达式前执行一个简短语句。该语句声明的变量作用域仅在 if 之内。
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10), // 9
pow(3, 3, 20), // 20
)
}
switch 分支
switch语句是编写一连串if-else语句的简便方法。一个case值等于条件表达式的子句且case值无需为常量,且取值不限于整数。Golang只会运行选定的case,与其他语言相比,相当于为每个case后面自动添加了break语句。Golang除非通过fallthrough语句继续执行后续分支的代码,否则分支会自动终止。switch的case语句从上到下顺次执行,直到匹配成功时停止。
k := 3
switch k {
case 1: fmt.Println("case 1");
case 2: fmt.Println("case 2");
case 3: fmt.Println("case 3"); fallthrough;
case 4: fmt.Println("case 4");
case 5: fmt.Println("case 5");
default: fmt.Println("default case")
}
运行结果为:
case 3
case 4
defer 推迟
defer语句会将函数推迟到外层函数返回之后执行。- 推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。
- 推迟调用的函数调用会被压入一个栈中(
LIFO:后进先出)。 当外层函数返回时,被推迟的调用会按照后进先出的顺序调用。
package main
import "fmt"
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Printf("%d\t", i)
}
fmt.Println("done")
}
运行结果为:
counting
done
9 8 7 6 5 4 3 2 1 0
Go 错误处理
Golang没有try/catch异常机制:不能执行抛异常操作。但是有一套defer-panic-and-recover机制,可以“捕捉”异常,也更轻量,并且只应该作为(处理错误的)最后的手段。
Golang有一个内建接口error类型:
type error interface {
Error() string
}
- 构造异常:
err := errors.New("异常信息") // error: "异常信息"
err := fmt.Errorf("错误信息: %v", "异常信息") // errors.New(fmt.Sprintf(...))
- 捕捉异常:判断错误是否等于
nil来进行错误处理。
func tryInt(s string) {
i, err := strconv.ParseInt(s, 0, 64)
if err == nil {
fmt.Println("Value:", i)
} else {
fmt.Println("Error:", err)
}
}
func main() {
tryInt("123123")
tryInt("123a123")
}
运行结果为:
Value: 123123
Error: strconv.ParseInt: parsing "123a123": invalid syntax
- 运行时异常
- 当发生像数组下标越界或类型断言失败这样的运行错误时,会触发运行时
panic,伴随着程序的崩溃抛出一个runtime.Error接口类型的值。 panic可以直接从代码初始化:当程序不能继续运行时,可以使用panic函数产生一个中止程序的运行时错误。
- 当发生像数组下标越界或类型断言失败这样的运行错误时,会触发运行时
panic("A severe error occurred: stopping the program!")
运行结果为:
Starting the program
panic: A severe error occurred: stopping the program!
......
- 从
panic中恢复- 内建函数
recover被用于从panic或错误场景中恢复。 recover只能在defer修饰的函数中使用:panic会导致栈被展开直到defer修饰的recover()被调用或者程序中止。
- 内建函数
package main
import "fmt"
func main() {
fmt.Println("Starting the program")
defer func() {
err := recover()
if err != nil {
fmt.Printf("捕捉异常: %T %v\n", err, err)
fmt.Println("Recover the program")
}
}()
panic("抛出异常")
fmt.Println("Ending the program")
}
运行结果为:
Starting the program
捕捉异常: string 抛出异常
Recover the program
END .
相关系列文章
- 「学习笔记」Golang -- GoFrame框架
- 「学习笔记」Golang -- Go协程 与 通道
- 「学习笔记」Golang -- 读写数据
- 「学习笔记」Golang -- 动态类型与反射
- 「学习笔记」Golang -- 控制语句与错误处理
- 「学习笔记」Golang -- 内置数据类型
- 「学习笔记」Golang -- 基础入门