Flow control statements: for, if, else, switch and defer

Flow control statements: for, if, else, switch and defer

For

原文:https://go.dev/tour/flowcontrol/1

​ Go 只有一个循环结构:for 循环。

​ 基本的for循环由三个部分组成,它们用分号隔开:

  • 初始化语句:在第一次迭代前执行
  • 条件表达式:在每次迭代前进行求值
  • 后置语句:在每次迭代的结尾执行。

​ 初始化语句通常是一个短变量声明,其中声明的变量只在for语句的作用域中可见。

​ 一旦条件表达式求值为false,循环迭代将停止。

注意:与其他语言如C、Java或JavaScript不同的是,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 continued - for (续)

原文:https://go.dev/tour/flowcontrol/2

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

 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 is Go’s “while”

原文:https://go.dev/tour/flowcontrol/3

​ 此时,您可以放弃分号。C的while在Go中叫做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)
}

Forever 无限循环

原文:https://go.dev/tour/flowcontrol/4

​ 如果您省略了循环条件,它就会永远循环下去。因此无限循环可以写得很紧凑。

1
2
3
4
5
6
package main

func main() {
	for {
	}
}

If

原文:https://go.dev/tour/flowcontrol/5

​ Go的if语句与它的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 with a short statement - if 的简短语句

原文:https://go.dev/tour/flowcontrol/6

​ 和for一样,if语句可以在条件表达式之前执行一个简短语句。

​ 该语句所声明变量的作用域仅在if之内。

​ (尝试在最后的return语句中使用v)。

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

If and else

原文:https://go.dev/tour/flowcontrol/7

​ 在if简短语句中声明的变量也可以在任何对应的else块中使用。

​ (对pow的两次调用都在main中对fmt.Println的调用开始之前返回其结果)。

 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)
	}
	// can't use v here, though
	return lim
}

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

Exercise: Loops and Functions 练习:循环和函数

原文:https://go.dev/tour/flowcontrol/8

​ 为了练习函数和循环,我们来实现一个平方根函数:给定一个数字x,我们想找到最接近x的数字z

​ 计算机通常使用循环来计算x的平方根。从某个猜测的z开始,我们可以根据x的接近程度来调整z,产生一个更好的猜测:

z -= (z*z - x) / (2*z)

​ 重复这种调整使猜测越来越精确,直到我们得到一个尽可能接近实际平方根的答案。

​ 在提供的函数Sqrt中实现这一点。无论输入什么,对z的一个合适的起始猜测是1。首先,重复计算10次,并打印每次的z值。观察对于不同的x值(1,2,3,……),您得到的答案是如何接近结果的,以及猜测提升的速度有多快。

提示:要声明和初始化一个浮点值,要给它以浮点的语法或使用转换:

1
2
z := 1.0
z := float64(1)

​ 接下来,修改循环条件,一旦数值停止变化(或者只变化了很小的量)就停止。观察迭代次数多于还是少于10次。尝试其他的z的初始猜测,比如x,或者x/2。您的函数的结果与标准库中的math.Sqrt有多接近?

(注:如果您对算法的细节感兴趣,上面的z²-x是指到它所要到达的值(即x)的距离,除以2z的导数,以缩放我们通过的变化速度调整z的程度。这种一般方法被称为牛顿法。它对许多函数都很有效,但对平方根尤其有效)。

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

import (
	"fmt"
)

func Sqrt(x float64) float64 {
}

func main() {
	fmt.Println(Sqrt(2))
}

Switch

原文:https://go.dev/tour/flowcontrol/9

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

​ Go的switch与C、C++、Java、JavaScript和PHP中的switch一样,只是Go只运行选定的case,而不是之后的所有情况。实际上,Go中是自动提供了在这些语言中每个case结尾所需的break语句。【除非在每个case语句结尾加上 fallthrough,否则case 分支会自动终止】。另一个重要的区别是,Go的switchcase无需是常量,且值也不必是整数。

 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.\n", os)
	}
}

Switch evaluation order

原文:https://go.dev/tour/flowcontrol/10

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

(例如:

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

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

Note: Time in the Go playground always appears to start at 2009-11-10 23:00:00 UTC, a value whose significance is left as an exercise for the reader.

注意: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
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 with no condition 没有条件的 switch

原文:https://go.dev/tour/flowcontrol/11

​ 没有条件的switchswitch true是一样的。

​ 这种形式能将一长串的if-then-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.")
	}
}

Defer

原文:https://go.dev/tour/flowcontrol/12

defer 语句将一个函数的执行推迟到外层函数返回的最后执行。

​ 推迟调用的函数的参数会被立即求值,但直到外层函数返回之前,该函数都不会被调用。

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}

Stacking defers

原文:https://go.dev/tour/flowcontrol/13

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

​ 要了解更多关于defer语句的信息,请阅读这篇博文

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

Congratulations!

原文:https://go.dev/tour/flowcontrol/14

​ 您完成了这一课!

​ 您可以回到模块列表中寻找下一步要学习的内容,或者继续学习下一课。

最后修改 February 5, 2024: 更新 (f57b279)