Go 学习笔记4-Go控制语句
目录
1,if 语句
if boolean_expression {
}
if boolean_expression {
} else {
}
// 多分支
if boolean_expression1 {
} else if boolean_expression2 {
} else if boolean_expressionN {
} else {
}
Go 支持在 if 后的布尔表达式前,进行一些变量的声明,在 if 布尔表达式前声明的变量,叫它 if 语句的自用变量。顾名思义,这些变量只可以在 if 语句的代码块范围内使用,比如下面代码中的变量 a、b 和 c:
func main() {
// 中间要用分号隔开
if a, c := f(), h(); a > 0 {
println(a)
} else if b := f(); b > 0 {
println(a, b)
} else {
println(a, b, c)
}
}
2,for 循环
Go 中的 for 循环有多种写法:
var sum int
for i := 0; i < 10; i++ {
sum += i
}
println(sum)
for i := 0; i < 10; {
i++
}
i := 0
for ; i < 10; {
println(i)
i++
}
i := 0
for i < 10 {
println(i)
i++
}
// 无限循环,死循环的三种种形式
for { // 最简洁,推荐使用
// 循环体代码
}
for true {
// 循环体代码
}
for ; ; {
// 循环体代码
}
3,for-range 语句
// 对于一个切片,用 for 循环遍历
var sl = []int{1, 2, 3, 4, 5}
for i := 0; i < len(sl); i++ {
fmt.Printf("sl[%d] = %d\n", i, sl[i])
}
// 等价的 for-range 遍历方法
for i, v := range sl {
fmt.Printf("sl[%d] = %d\n", i, v)
}
// for-range 的几个变种
// 只遍历下标值
for i := range sl {
// ...
}
// 只遍历值,忽略下标
for _, v := range sl {
// ...
}
// 既不关心下标,也不关心值
for range sl {
// ...
}
遍历 string 类型:
var s = "中国人"
for i, v := range s {
fmt.Printf("%d %s 0x%x\n", i, string(v), v)
}
// 结果如下
0 中 0x4e2d
3 国 0x56fd
6 人 0x4eba
for-range 与 channel
当 channel 类型变量作为 for range 语句的迭代对象时,for range 会尝试从 channel 中读取数据:
var c = make(chan int)
for v := range c {
// ...
}
- for range 每次从 channel 中读取一个元素后,会把它赋值给循环变量 v,并进入循环体
- 当 channel 中没有数据可读的时候,for range 循环会阻塞在对 channel 的读操作上
- 直到 channel 关闭时,for range 循环才会结束,这也是 for range 循环与 channel 配合时隐含的循环判断条件
for range 与 Goroutine 的坑
比如下面代码:
func main() {
var m = []int{1, 2, 3, 4, 5}
for i, v := range m {
go func() {
time.Sleep(time.Second * 3)
fmt.Println(i, v)
}()
}
time.Sleep(time.Second * 10)
}
// 其实际输出是
4 5
4 5
4 5
4 5
4 5
//
func main() {
var m = []int{1, 2, 3, 4, 5}
for i, v := range m {
go func(i, v int) {
time.Sleep(time.Second * 3)
fmt.Println(i, v)
}(i, v)
}
time.Sleep(time.Second * 10)
}
// 输出的结果如下(具体的结果依赖于 CPU 调度)
0 1
1 2
2 3
3 4
4 5
4,continue 与 break 语句
Go 语言提供了 continue 语句和 break 语句。
Go 语言中的 continue 在 C 语言 continue 语义的基础上又增加了对 label 的支持。
带 label 的 continue 语句,通常出现于嵌套循环语句中,被用于跳转到外层循环并继续执行外层循环语句的下一个迭代,比如:
func main() {
var sl = [][]int{
{1, 34, 26, 35, 78},
{3, 45, 13, 24, 99},
{101, 13, 38, 7, 127},
{54, 27, 40, 83, 81},
}
outerloop:
for i := 0; i < len(sl); i++ {
for j := 0; j < len(sl[i]); j++ {
if sl[i][j] == 13 {
fmt.Printf("found 13 at [%d, %d]\n", i, j)
continue outerloop
}
}
}
}
5,switch-case 语句
func readByExtBySwitch(ext string) {
switch ext {
case "json":
println("read json file")
case "jpg", "jpeg", "png", "gif":
println("read image file")
case "txt", "md":
println("read text file")
case "yml", "yaml":
println("read yaml file")
case "ini":
println("read ini file")
default:
println("unsupported file extension:", ext)
}
}
如果 switch 表达式匹配到了某个 case 表达式,那么程序就会执行这个 case 对应的代码分支。这个分支后面的 case 表达式将不会再得到求值机会,即便后面的 case 表达式求值后也能与 switch 表达式匹配上,Go 也不会继续去对这些表达式进行求值了。
无论 default 分支出现在什么位置,它都只会在所有 case 都没有匹配上的情况下才会被执行的。
只要类型支持比较操作,都可以作为 switch 语句中的表达式类型。比如整型、布尔类型、字符串类型、复数类型、元素类型都是可比较类型的数组类型,甚至字段类型都是可比较类型的结构体类型,也可以。
6,type-switch 语句
Go 语言的 switch 语句还支持求值结果为类型信息的表达式,也就是 type switch 语句。
func main() {
// x 必须是一个接口类型变量
// 通过x.(type),可以获得变量 x 的动态类型信息
var x interface{} = 13
switch x.(type) {
case nil:
println("x is nil")
case int:
println("the type of x is int")
case string:
println("the type of x is string")
case bool:
println("the type of x is string")
default:
println("don't support the type")
}
}
通过x.(type),我们除了可以获得变量 x 的动态类型信息之外,也能获得其动态类型对应的值信息:
func main() {
var x interface{} = 13
// v 存储的是变量 x 的动态类型对应的值信息
switch v := x.(type) {
case nil:
println("v is nil")
case int:
println("the type of v is int, v =", v)
case string:
println("the type of v is string, v =", v)
case bool:
println("the type of v is bool, v =", v)
default:
println("don't support the type")
}
}
// 输出结果如下
the type of v is int, v = 13
(完。)
文章作者 @码农加油站
上次更改 2022-06-07