在 Go 中只有很少的几个控制结构 。这里没有 do 或者 while 循环,只有 for。有(灵活的) switch 语句和 if,而 switch 接受像 for 那样可选的初始化语句。还有叫做类型选择和多路通讯转接器的 select。同 C 相比语法有所不同:无需圆括号,而语句体必须总是包含在大括号内。
1、if-else
Go 中的 if 和 C 语言中的 if 很相似,区别主要有三点:
- 执行体必须要有大括号,且左大括号必须和 if(或 else) 在同一行即使只有一条语句;
- 条件语句不需要圆括号;
- 条件语句中可以包含初始化语句,通常用于设置一个(局部)遍量。
if x > 0 { // 左括号必须在同一行
return y
} else {
return x
}
if f, err := os.Open(name); err != nil { // 带初始化语句的条件语句
return err
}
Go 编译器关于if-else
的一个 bug
//注意如果在函数中这样结束,它不会编译。
if err ! = nil {
return err
} else {
return nil
}
2、goto
Go 有 goto 语句 — 明智的使用它。用 goto 跳转到一定是当前函数内定义的标签,且标签是大小写敏感的。
例如假设这样一个循环:
func myfunc() {
i := 0
Here: // 这行的第一个词,以分号结束作为标签
println(i)
i++
goto Here // 跳转
}
3、for 循环
Go 中没有 while
和 do...while
循环,只有 for
循环,可以使用for
实现 while
的功能。
Go 的 for 循环有三种形式,只有其中的一种使用分号。
for init; condition; post { } // 和 C 的 for 一样
for condition { } // 和 while 一样
for { } // 死循环, 和 C 的 for(;;) 一样
例如,使用 for 计算 0~9 的和:
sum := 0
for i := 0; i < 10; i++ {
sum += i // sum = sum + i 的简化写法
}
**注意:**Go 没有逗号表达式,而 ++ 和 – 是语句而不是表达式,如果你想在 for 中执行多个变量,应当使用平行赋值,形式为i, j = ival, jval
。
// 翻转数组 a
for i, j := 0, len(a)-1; i < j ; i, j = i+1, j-1 { // 平行赋值
a[i], a[j] = a[j], a[i] // 这里也是
}
4、break 和 continue
Go 中的 break 、continue 与 C 语言中的很相似,只是 Go 中的 break 可以添加标签,表示退出哪一层循环,因此,Go 中的 break 可以退出多层循环,而 C 语言中的 break 只能退出 1层循环。
for i := 0; i < 10; i++ {
if i > 5 {
break // 终止这个循环,只打印 0 到 5
}
println(i)
}
/* 使用标签,退出多层循环 */
J: for j := 0; j < 5; j++ {
for i := 0; i < 10; i++ {
if i > 5 {
break J //现在终止的是 j 循环,而不是 i 的那个
}
println(i)
}
}
5、range
range 可用于循环。它可以对 slice、 array、 string、 map 和 channel 进行循环遍历。 range 是个迭代器,当被调用的时候,从它循环的内容中返回一个键-值对。基于不同的内容, range 返回不同的东西。
当对 slice 或者 array 做循环时, range 返回序号作为键,这个序号对应的内容作为值。
// 遍历数组
list := [] string{"a", "b", "c", "d", "e", "f" }
for k, v := range list { // k-v 键值对,k 为索引(从 0 开始),v 为对应的值
// 对 k 和 v 做想做的事情
}
也可以在字符串上直接使用 range。这样字符串被打散成独立的 Unicode 字符,并且起始位按照 UTF-8 解析。
for pos, char := range "aΦx" {
fmt.Printf("character '%c' starts at byte position %d\n", char, pos)
}
// 执行后打印输出
character 'a' starts at byte position 0
character 'Φ' starts at byte position 1 // Φ占用两个字节
character 'x' starts at byte position 3
6、switch
Go 的 switch 非常灵活。表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项,如果没有匹配项就执行 default 中的语句(如果有 default);而如果 switch 没有表达式,它会匹配 true 。这产生一种可能 — 使用 switch 编写 if-else-if-else 判断序列。
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
注意: switch 不会执行完一个 case
后继续执行下面的 case
,但是可以使用关键字 fallthrough
使其继续执行。
switch i {
case 0: // 空的 case 体
case 1:
f() // 当 i == 0 时, f 不会被调用!
}
/* 使用 fallthrough 使执行多个 case */
switch i {
case 0: // 空的 case 体
fallthrough
case 1:
f() // 当 i == 0 或 1 时,f 被调用!
}
分支可以使用逗号分隔的列表。
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+': // 相当于 "or"
return true
}
return false
}
7、select
Go 可以通过关键字 select 监听 channel 上的数据流动。
select 默认是阻塞的, 只有当监听的 channel 中有发送或接收可以进行时才会运行, 当多个 channel 都准备好的时候, select 是随机的选择一个执行的。
在select 里面可以有 default语法, select 其实就是类似 switch 的功能, default 就是当监听的channel 都没有准备好的时候, 默认执行的( select 不再阻塞等待 channel)。
L: for {
select {
case <-c:
i++
if i > 1 { // 当接收到一个数据时退出循环
break L
}
}
}
有疑问加站长微信联系(非本文作者)