在 Go 中只有很少的几个控制结构 。这里没有 do 或者 while 循环,只有 for。有(灵活的) switch 语句和 if,而 switch 接受像 for 那样可选的初始化语句。还有叫做类型选择和多路通讯转接器的 select。同 C 相比语法有所不同:无需圆括号,而语句体必须总是包含在大括号内。
Go 中的 if 和 C 语言中的 if 很相似,区别主要有三点:
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}
Go 有 goto 语句 — 明智的使用它。用 goto 跳转到一定是当前函数内定义的标签,且标签是大小写敏感的。
例如假设这样一个循环:
func myfunc() {
i := 0Here: // 这行的第一个词,以分号结束作为标签
println(i)
i++ goto Here // 跳转}
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 := 0for i := 0; i < 10; i++ {
sum += i // sum = sum + i 的简化写法}
**注意:**Go 没有逗号表达式,而 ++ 和 – 是语句而不是表达式,如果你想在 for 中执行多个变量,应当使用平行赋值,形式为i, j = ival, jval
。
// 翻转数组 afor i, j := 0, len(a)-1; i < j ; i, j = i+1, j-1 { // 平行赋值
a[i], a[j] = a[j], a[i] // 这里也是}
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)
}
}
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 0character 'Φ' starts at byte position 1 // Φ占用两个字节character 'x' starts at byte position 3
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}
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
}
}
}