Golang-2-流程控制语句

Parts of A Tour Of Go

for

Go只有一种循环结构: for循环

基本的for循环由三部分组成,用分号;隔开

  • 初始化语句: 在第一次迭代前执行
  • 条件表达式: 在每次迭代前求值
  • 后置语句: 在每次迭代的结尾执行
1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}

初始化语句通常为一句短变量声明,该变量声明仅在for语句的作用域中可见。
CJavaJavaScript之类的语言不同之处在于Gofor语句后面没有小括号。

for的初始化语句和后置语句是可选的

1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
sum := 1
for ; sum < 1000; {
sum += sum
}
fmt.Println(sum)
}

forGo中的while

去掉for中的分号;,实现while

1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}

for实现无限循环

如果省略循环条件,该循环就不会结束。

1
2
3
4
5
6
7
package main

func main() {
for {
// TODO
}
}

if

Goif语句与for循环类型,表达式无需使用小括号(),而大括号{}则是必须的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"math"
)

func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}

func main() {
fmt.Println(sqrt(2), sqrt(-4))
}

if的简短语句

for一样,if可以在条件表达式之前执行一个简短语句。
该语句声明的变量作用域仅在if内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"math"
)

func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}

func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}

ifelse

if的简短语句中声明的变量同样可以在对应的else中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"math"
)

func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
// 这里开始变量v就不能使用了
return lim
}

func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}

练习: 循环和函数

用牛顿法实现平方根函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"math"
)

func Sqrt(x float64) float64 {
if x <= 0 {
return x
}
sqrt := 1.0
for i := 0; i < 10; i++ {
sqrt = (sqrt + x/sqrt) / 2
}
return sqrt
}

func main() {
x := float64(222)
fmt.Println(Sqrt(x))
fmt.Println(math.Sqrt(x))
}

switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"runtime"
)

func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd
// plan9, windows
fmt.Printf("%s.", os)
}
}

switchcase语句从上到下顺序执行,直到匹配成功时停止。

1
2
3
4
5
// 当i等于0的时候,f不会被调用
switch i {
case 0:
case f():
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"time"
)

func main() {
fmt.Println("When's Saturday?")
today := time.Now().Weekday()
switch time.Saturday {
case today + 0:
fmt.Println("Today.")
case today + 1:
fmt.Println("Tomorrow.")
case today + 2:
fmt.Println("In two days.")
default:
fmt.Println("Too far away.")
}
}

没有条件的switch语句能使一长串的if-else语句写得更加清晰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
"time"
)

func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "fmt"

func main() {
var i int = 0
for {
switch i += 1; i {
// 匹配多条
case 1, 2, 3, 4, 5, 6:
fmt.Println("Small One ", i)
default:
fmt.Println("Fine")
return
}
}
}

defer

defer语句可以将函数推迟到外层函数返回时执行。
推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。

1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

func main() {
t := "world"
defer fmt.Println(t)
t = "hello"
fmt.Println(t)
}

推迟调用的函数会被压入到一个栈中(defer栈),当外层函数返回时,被推迟调用的函数会按照后进先出(LIFO)的顺序调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func main() {
fmt.Println("counting")

for i := 0; i < 10; i++ {
defer fmt.Println(i)
}

fmt.Println("DONE")
}