这是我参与「第五届青训营」伴学笔记创作活动的第 3 天
前言
学习过程中发现对go语言中许多关键字比较陌生,因此在本文中对go语言中的常用关键字进行了总结。
for-range
for-range是go语言中除了for的三段式循环外的另一循环语句,在形式上for-range循环相比于三段式循环更为简洁。两者在编译后具有相同的汇编代码,使用 for-range 的控制结构最终也会被 go 语言编译器转换成普通的 for 循环。
数组和切片
//返回索引
for i := range a {}
//返回索引和数据
for i, elem := range a {}
//返回数据
for _, elem := range a {}
- 在使用for-range遍历数组和切片时,可以获取索引和数据,只有一个变量时默认获取索引。
- 在编译期间go语言会将切片或者数组赋值给一个新变量并预先获取数组或切片的长度,所以在循环中若追加了新元素并不会改变循环执行的次数。
哈希表
//返回键
for key := range hash {}
//返回键和值
for key, val := range hash {}
//返回值
for _, elem := range hash {}
哈希表的遍历首先会随机选出一个正常桶开始遍历,随后遍历所有溢出桶,最后依次按照索引顺序遍历哈希表中其他的桶,直到所有的桶都被遍历完成。
字符串
遍历字符串的过程与数组、切片和哈希表非常相似,只是在遍历时会获取字符串中索引对应的字节并将字节转换成 rune。
管道
用range遍历管道时只会返回元素这一个值,不存在第二个值,即 for v := range ch {} 。
select
select是操作系统中的系统调用,使用select、poll 和 epoll 等函数构建I/O多路复用模型提升程序的性能。go语言的select能够让Goroutine同时等待多个Channel可读可写,在多个文件或者Channel状态改变之前,select会一直阻塞当前线程或者Goroutine。
select与switch有相似的控制结构,与 switch 不同的是,select 中虽然也有多个 case,但是这些 case 中的表达式必须都是 Channel 的收发操作。
// 示例
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
defer
go语言的defer用于资源释放,如关闭文件描述符、关闭数据库连接以及解锁资源,在当前函数返回前调用执行,如果有多个defer,调用顺序类似于栈,越后面的defer表达式越优先被调用。
在含有defer表达式的函数中函数返回的过程如下:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。
//示例
func f() (result int) {
defer func() {
result++
}()
return 0
} // return 1
func f() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
} // return 5
func f() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
} // return 1
panic 和 recover
panic :改变程序的控制流,调用 panic 后会立刻停止执行当前函数的剩余代码,并在当前 Goroutine 中递归执行调用方的 defer。
recover: 可以中止 panic 造成的程序崩溃。它是一个只能在 defer 中发挥作用的函数,在其他作用域中调用不会发挥作用。