if-else 结构
• 可省略条件表达式括号。
• ⽀持初始化语句,可定义代码块局部变量。
• 代码块左⼤括号必须在条件表达式尾部。
x := 0 // if x > 10 // Error: missing condition in if statement // { // } if n := "abc"; x > 0 { // 初始化语句未必就是定义变量,⽐如 println("init") 也是可以的。 println(n[2]) } else if x < 0 { // 注意 else if 和 else 左⼤括号位置。 println(n[1]) } else { println(n[0]) }
注意:不⽀持三元操作符 “a > b ? a : b”。
注意:关键字 if 和 else 之后的左大括号 { 必须和关键字在同一行,如果你使用了 else-if 结构,则前段代码块的右大括号 } 必须和 else-if 关键字在同一行。这两条规则都是被编译器强制规的。
For
⽀持三种循环⽅式,但while并不是go的关键字,不能用来写循环。
s := "abc" for i, n := 0, len(s); i < n; i++ { // 常⻅的 for 循环,⽀持初始化语句。 println(s[i]) } n := len(s) for n > 0 { // 替代 while (n > 0) {} println(s[n]) // 替代 for (; n > 0;) {} n-- } for { // 替代 while (true) {} println(s) // 替代 for (;;) {} }
不要期望编译器能理解你的想法,在初始化语句中计算出全部结果是个好主意。
func length(s string) int { println("call length.") return len(s) } func main() { s := "abcd" for i, n := 0, length(s); i < n; i++ { // 避免多次调⽤ length 函数。 println(i, s[i]) } }
输出:
call length.
0 97
1 98
2 99
3 100
Range
类似迭代器操作,返回 (索引, 值) 或 (键, 值)。可忽略不想要的返回值,或⽤ “_” 这个特殊变量。
s := "abc" for i := range s { // 忽略 2nd value,⽀持 string/array/slice/map。 println(s[i]) } for _, c := range s { // 忽略 index。 println(c) } for range s { // 忽略全部返回值,仅迭代。 ... } m := map[string]int{"a": 1, "b": 2} for k, v := range m { // 返回 (key, value)。 println(k, v) }
注意: range 会复制对象。
a := [3]int{0, 1, 2} for i, v := range a { // index、value 都是从复制品中取出。 if i == 0 { // 在修改前,我们先修改原数组。 a[1], a[2] = 999, 999 fmt.Println(a) // 确认修改有效,输出 [0, 999, 999]。 } a[i] = v + 100 // 使⽤复制品中取出的 value 修改原数组。 } fmt.Println(a) // 输出 [100, 101, 102]。
在多数情况下,建议改⽤引⽤类型,其底层数据不会被复制,能提高程序的负载性能
s := []int{1, 2, 3, 4, 5} for i, v := range s { // 复制 struct slice { pointer, len, cap }。 if i == 0 { s = s[:3] // 对 slice 的修改,不会影响 range。 s[2] = 100 // 对底层数据的修改。 } println(i, v) }
输出:
0 1
1 2
2 100
3 4
4 5
Switch
分⽀表达式可以是任意类型,不限于常量。可省略 break,默认⾃动终⽌。
x := []int{1, 2, 3} i := 2 switch i { case x[1]: println("a") case 1, 3: println("b") default: println("c") }
输出:
a
如需要继续下⼀分⽀,可使⽤ fallthrough,但不再判断条件。
x := 10 switch x { case 10: println("a") fallthrough case 0: println("b") }
输出:
a
b
Goto, Break, Continue
⽀持在函数内 goto 跳转。标签名区分⼤⼩写,未使⽤标签引发错误。
func main() { var i int for { println(i) i++ if i > 2 { goto BREAK } } BREAK: println("break") EXIT: // Error: label EXIT defined and not used }
配合标签,break 和 continue 可在多级嵌套循环中跳出。
func main() { L1: for x := 0; x < 3; x++ { L2: for y := 0; y < 5; y++ { if y > 2 { continue L2 } if x > 1 { break L1 } print(x, ":", y, " ") } println() } }
输出:
0:0 0:1 0:2
1:0 1:1 1:2
注意:break 可⽤于 for、switch、select,⽽ continue 仅能⽤于 for 循环。