Go 入门 (二)-- 控制语句

1. 控制语句

1.1. 唯一循环结构: for

1.1.1. for 循环

Go 只有一种循环结构:for 循环。
基本的 for 循环由三部分组成,它们用分号隔开:

  1. 初始化语句:在第一次迭代前执行(可选)
  2. 条件表达式:在每次迭代前求值(可选)
  3. 后置语句:在每次迭代的结尾执行

初始化语句通常为一句短变量声明,该变量声明仅在 for 语句的作用域中可见。
一旦条件表达式的布尔值为 false,循环迭代就会终止。
注意:和 C、Java、JavaScript 之类的语言不同,Go 的 for 语句后面的三个构成部分外没有小括号, 大括号 { } 则是必须的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main

import "fmt"

func sum(toEnd int) int {
sum := 0
for i := 1; i <= toEnd; i++ {
sum += i
}
return sum
}

func sum2(toEnd int) int {
sum := 0
i := 1
for ; i <= toEnd; {
sum += i
i++
}
return sum
}

func equalWhile(toEnd int) int {
sum := 0;
i := 1;
for i <= toEnd {
sum += i
i++
}
return sum
}


func main() {
toEnd := 100;
total := sum(toEnd);
fmt.Printf("Sum 1 to %v is : %v", toEnd, total)
total2 := sum2(toEnd);
fmt.Printf("Sum2 1 to %v is : %v", toEnd, total2)
total3 := equalWhile(toEnd);
fmt.Printf("Sum 1 to %v by func equalWhile is : %v", toEnd, total3)
}

输出结果:
Sum 1 to 100 is : 5050
Sum2 1 to 100 is : 5050
Sum 1 to 100 by func equalWhile is : 5050

1.1.2. 无限循环

如果省略循环条件,该循环就不会结束,因此无限循环可以写得很紧凑。

1
2
3
4
5
6
package main

func main() {
for {
}
}

1.2. 条件控制

1.2.1. if

Go 的 if 语句与 for 循环类似,表达式外无需小括号 ( ) ,而大括号 { } 则是必须的。

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"
"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))
}

输出结果:
1.4142135623730951 2i

1.2.2. if 的简短语句

同 for 一样, if 语句可以在条件表达式前执行一个简单的语句。
该语句声明的变量作用域仅在 if 之内。
(在最后的 return 语句处使用 v 看看。)// 报错,找不到 v

在 if 的简短语句中声明的变量同样可以在任何对应的 else 块中使用。
(在 main 的 fmt.Println 调用开始前,两次对 pow 的调用均已执行并返回其各自的结果。)

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

import (
"fmt"
"math"
)

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

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

输出结果:
9
27 >= 10
27 >= 10
10

1.3. 用牛顿法实现平方根函数

参考 https://tour.go-zh.org/flowcontrol/8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package main

import (
"fmt"
"math"
)

// 固定10次
func Sqrt10(number float64) float64 {
z := float64(1)
for i := 0; i < 10; i++ {
z -= (math.Pow(z, 2) - number) / (2 * z)
fmt.Printf("%v z is %v\n", i+1, z)
}
return z;
}

// 设置当值小于指定的差值时,结束循环
func Sqrt(number, error, z float64) float64 {
fmt.Printf("Start to sqrt number : %v, from z : %v \n",number,z)
loopCount := 1;
for math.Abs(math.Sqrt(number) - z) > error {
z -= (math.Pow(z, 2) - number) / (2 * z)
fmt.Printf("%v z is %v\n", loopCount, z)
loopCount++
}
return z;
}

func main() {
number := float64(3);
fmt.Println(Sqrt10(number))
fmt.Println("--------------------------")
fmt.Println(Sqrt(number, 0.001,1))
fmt.Println("--------------------------")
fmt.Println(Sqrt(number, 0.001,number))
fmt.Println("--------------------------")
fmt.Println(Sqrt(number, 0.001,number /2 ))
}

输出结果:
1 z is 2
2 z is 1.75
3 z is 1.7321428571428572
4 z is 1.7320508100147276
5 z is 1.7320508075688772
6 z is 1.7320508075688774
7 z is 1.7320508075688772
8 z is 1.7320508075688774
9 z is 1.7320508075688772
10 z is 1.7320508075688774
1.7320508075688774
--------------------------
Start to sqrt number : 3, from z : 1
1 z is 2
2 z is 1.75
3 z is 1.7321428571428572
1.7321428571428572
--------------------------
Start to sqrt number : 3, from z : 3
1 z is 2
2 z is 1.75
3 z is 1.7321428571428572
1.7321428571428572
--------------------------
Start to sqrt number : 3, from z : 1.5
1 z is 1.75
2 z is 1.7321428571428572
1.7321428571428572

1.4. switch 语句

switch 是编写一连串 if - else 语句的简便方法。它运行第一个值等于条件表达式的 case 语句。

Go 的 switch 语句类似于 C、C++、Java、JavaScript 和 PHP 中的,不过 Go 只运行选定的 case,而非之后所有的 case。 实际上,Go 自动提供了在这些语言中每个 case 后面所需的 break 语句。 除非以 fallthrough 语句结束,否则分支会自动终止。 Go 的另一点重要的不同在于 switch 的 case 无需为常量,且取值不必为整数。

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

import (
"fmt"
"runtime"
)

func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
fallthrough // 继续执行下一个 case
case "linux":
fmt.Println("Linux.")
case "win":
fmt.Println("Windows.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Println("%s.\n", os)
}
}

输出结果:
Go runs on OS X.
Linux.

1.4.1. switch 的求值顺序

switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。
(例如,

1
2
3
4
switch i {
case 0:
case f():
}

在 i==0 时 f 不会被调用。)

注意: Go 练习场中的时间总是从 2009-11-10 23:00:00 UTC 开始,该值的意义留给读者去发现。(首次公开发布)

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

import (
"fmt"
"time"
)

func main() {
fmt.Print("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 tow days.")
//case 6:
// fmt.Println("Now.")
default:
fmt.Println("Too far away.")
}
}

输出结果:
When's Saturday? Too far away.

1.4.2. 没有条件的 switch 语句

没有条件的 switch 同 switch true 一样。
这种形式能将一长串 if-then-else 写得更加清晰。

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() {
now := time.Now()
switch {
case now.Hour() < 12:
fmt.Println("Good morning!")
case now.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening .")
}
}

输出结果:
Good evening .

1.5. defer 语句 (类似 Java finally)

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

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

import "fmt"

func outter() {
defer fmt.Print(" World")
fmt.Print("Hello")
}

func main() {
outter()
}

输出结果:
Hello World

###defer 栈
推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
更多关于 defer 语句的信息,请阅读此博文https://blog.go-zh.org/defer-panic-and-recover

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

import "fmt"

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

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

fmt.Println("done")
}

输出结果:
counting
done
9
8
7
6
5
4
3
2
1
0
Just for my love !!