2.流程控制语句
(一)for循环
区别于cpp、js、java,Go只有一种循环结构,也就是for循环。 基本的for循环由三个部分构成,他们使用分号进行分隔:
初始化语句:i:=0; 条件表达式:在每次迭代前进行求值操作,i<xxx;i++ 后置语句:在每次迭代的结尾执行
初始化语句通常为短变量声明语句,该变量语句仅在 for语句的作用域中可见。
一旦表达式求值为false循环迭代将会终止。
注意:和cpp、java、js等语言不同,Go 的 for 语句后面的三个构成部分外没有小括号, 大括号 { } 则是必须的。
ps:初始化语句和后置语句是可选的。
示例:
Go1package main2 3import "fmt"4 5func main() {6 sum := 07 for i := 0; i < 10; i++ {8 sum += i9 }10 fmt.Println(sum)11}
如果你删去分号,前置初始化语句,只保留条件表达式,这就是和cpp中的while拥有相同功能的“while”。
示例:
Go1 2package main3 4import "fmt"5 6func main() {7 sum := 18 for sum < 1000 {9 sum += sum10 }11 fmt.Println(sum)12}
如果你需要使用无限循环,你只需要省略循环条件,这个循环就不会结束,所以你会发现无限循环可以写的非常紧凑。
示例:
Go1package main2 3func main() {4 for {5 }6}
(二)if判断语句
go的if判断和js、cpp等非常相似,只是在表达式外无需使用圆括号包裹。但是花括号是必须的。
示例:
Go1 2package main3 4import (5 "fmt"6 "math"7)8 9func sqrt(x float64) string {10 if x < 0 {11 return sqrt(-x) + "i"12 }13 return fmt.Sprint(math.Sqrt(x))14}15 16func main() {17 fmt.Println(sqrt(2), sqrt(-4))18}
注意:和for一样,if语句可以在条件表达式前执行一个简短语句。
该语句声明的变量作用域仅在 if 之内。也就是块级作用域的定义,相当于JS中的let定义。
示例:
Go1package main2 3import (4 "fmt"5 "math"6)7 8func pow(x, n, lim float64) float64 {9 if v := math.Pow(x, n); v < lim {10 return v11 }12 return v //输出为undefined13}14 15func main() {16 fmt.Println(17 pow(3, 2, 10),18 pow(3, 3, 20),19 )20}
如果使用else,那简短语句定义的变量同样可以在对应的任何 else 块中使用。
示例:
(在 main 的 fmt.Println 调用开始前,两次对 pow 的调用均已执行并返回其各自的结果。)
Go1package main2 3import (4 "fmt"5 "math"6)7 8func pow(x, n, lim float64) float64 {9 if v := math.Pow(x, n); v < lim {10 return v11 } else {12 fmt.Printf("%g >= %g\n", v, lim)13 }14 // can't use v here, though15 return lim16}17 18func main() {19 fmt.Println(20 pow(3, 2, 10),21 pow(3, 3, 20),22 )23}
(三)switch分支语句
switch语句和 C++、Java、JavaScript 和 PHP 中的switch语句相似但有两点不同。
在效果上,Go 的做法相当于这些语言中为每个 case 后面自动添加了所需的 break 语句,不需要再添加break。
另外一点不同在于case不需要特定为常量,且取值可以不限于整数。
示例:
Go1 2 package main3 4import (5 "fmt"6 "runtime"7)8 9func main() {10 fmt.Print("Go 运行的系统环境:")11 switch os := runtime.GOOS; os {12 case "darwin":13 fmt.Println("macOS.")14 case "linux":15 fmt.Println("Linux.")16 default:17 // freebsd, openbsd,18 // plan9, windows...19 fmt.Printf("%s.\n", os)20 }21}
注意:switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。
无条件的switch和多个if else的功能相似,无条件switch等同于switch true。
(四)defer 推迟 (关键字)
defer语句会让后面跟随的函数推迟到外部函数返回后再执行。defer实现的效果类似promise then的效果,在父函数执行完成后再调用该函数。
注意:使用defer关键字推迟调用的函数,函数的参数会立即进行求值,但是直到外层函数返回前都不会调用
ps:使用defer关键字推迟的函数会被压入栈中,当外层函数返回时,被推迟的调用会按照后进先出的顺序调用。
示例:
Go1 2package main3 4import "fmt"5 6func main() {7 fmt.Println("counting")8 9 for i := 0; i < 10; i++ {10 defer fmt.Println(i)11 }12 13 fmt.Println("done")14}