|
For
Go只有一种循环结构,那就是for循环。
一般形式
虽然只有一种循环,但为了满足不同的需求,也提供了许多形式,一般形式如下:
- initialization部分:在循环开始之前进行;一般是变量的初始化;
- condition部分:每次循环之前都要执行;一般是布尔表达式,判断为真则循环,判断为假则结束循环;
- post部分:在每次循环迭代结束之后都要执行;一般是对condition部分的变量进行修改;
condition部分在下一次循环之前再次进行判断,如此往复,形成循环。
示例:for.go
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
注意点:
for循环的大括号不可省略,且左括号必须和for循环在一行上。
如果for循环部分写成:
for i := 0; i < 10; i++
{
sum += i
}
执行会报错:
# command-line-arguments
.\for.go:7: syntax error: missing { after for clause
for循环initialization部分的变量仅可用于for循环部分,在for循环体之外不可使用。
在fmt.Println(sum)下添加语句fmt.Println(i)执行会报错:
# command-line-arguments
.\for.go:11: undefined: i
省略形式
initialization部分和post部分可省略;
示例:
package main
import "fmt"
func main() {
sum := 1
for ; sum < 1000; {
sum += sum
}
fmt.Println(sum)
}
以上代码中的for循环部分,在LiteIDE中执行时会自动变为:
for sum < 1000 {
sum += sum
}
initialization部分和post部分可以省略,分号也可以省略,这也是for的另一种形式。
condition部分可省略
如果省略condition部分,循环将永久执行(即 死循环)。
示例:forever.go
package main
func main() {
for {
}
}
If
If
Go的if语句和它的for循环语句很相似:
表达式不需要圆括号;但大括号却是必需的,且左大括号不能单独在一行。
示例:if.go
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结束之前使用,即作用域是if语句中。
示例:if-with-a-short-statement.go
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, 2, 20),
pow(3, 2, 8),
)
}
如果在return lim语句的上面添加语句fmt.Println(v),执行报错:
# command-line-arguments
.\if-with-a-short-statement.go:12: undefined: v
if - else
在if - else语句中,在if中声明的变量在else代码块中依然可以使用。
示例:if-and-else.go
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)
}
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 2, 20),
pow(3, 2, 7),
)
}
Switch
看看switch的形式,是不是似曾相似?
在switch语句中使用的表达式必须具有整数或布尔表达式,或者是一个具有单个转换函数为整数或布尔值的类类型。如果未传递表达式,则默认值为true。
在switch语句中可以有任意数量的case语句。 每个case后面都跟要比较的值和冒号。
case的常量表达式必须是与switch语句的变量是相同的数据类型,并且它必须是常量或文字。
当被switch打开的变量等于一个case中的值,那么将执行case之后的语句。在case语句中不需要break语句。
switch语句可有一个可选的 default,它必须出现在switch语句的末尾。 default可用于在没有任何 case 为真时执行任务。default之后也不需要 break 语句。
switch语句能够简化if-else语句,尤其是当if-else比较复杂时。
示例:switch.go
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)
}
}
switch的case判断顺序是自上而下的,当某一个case匹配成功时停止。
Defer
defer语句(和其机制)我还是第一次碰到。defer这个单词是延迟的意思,相必是Go语言为了某种特定需求而提供的一种机制,隐约觉得它必有大用途。
defer语句延迟函数的执行,直到周围的函数已返回。
示例:defer.go
package main
import "fmt"
func main() {
v := 2
defer fmt.Println("v is:", v)
v = v + 1
fmt.Println("v now is:", v)
defer fmt.Println("v is:", v)
v = v + 1
fmt.Println("v now is:", v)
}
输出:
v now is: 3
v now is: 4
v is: 3
v is: 2
从上面例子中还能看出,defer语句中的变量的值早已确定,但函数的调用是延迟的。
Stacking defers
延迟的栈调用被压入到一个栈中。当函数返回时,它的延迟调用按照后进先出的顺序被执行。
示例:defer-multi.go
package main
import "fmt"
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
//defer fmt.Println(i)
fmt.Println(i)
}
fmt.Println("done")
}
结果:
counting
0
1
2
3
4
5
6
7
8
9
done
如果将fmt.Println(i)修改为defer fmt.Println(i):
counting
done
9
8
7
6
5
4
3
2
1
0
小结
流程控制语句的主要内容就这么多,有了这些基础,你可以读读其它Go教材的有关部分做个补充,或者找些其它编程语言的流程控制语句的练习题,用Go来实现。
|
|