本文最初发表在我的个人博客,查看原文,获得更好的阅读体验
Go中关于流程控制方面主要有if-else,for循环,switch。另外,Go中还多了一种新的控制结构select,这种结构包含一个类型开关和一个多路通信复用器;if和switch接受类似for的可选初始化语句;break,continue和goto语句采用可选标签来标识要中断或继续以及要跳转的内容;与C相比,Go的控制结构语法也有些区别:没有小括号,并且控制体必须包含在一对大括号中。
关于select的用法,将在后续关于并发的文章中讲。
if表达式外无需小括号 ( ) ,而大括号 { } 则是必须的。强制使用大括号是为了鼓励将简单的if语句拆分成多行。这是一个好习惯,特别是当控制体中包含return或break语句时。
在Go中,一个简单的if语句如下:
if x > 0 { return y; }示例:
package main import ( "fmt" "math" ) func main() { fmt.Println(sqrt(16)) fmt.Println(sqrt(-9)) } func sqrt(x float64) string { if x < 0 { return sqrt(-x) + "i" } return fmt.Sprint(math.Sqrt(x)) }if 语句可以在条件表达式前执行一个简单的语句。该语句声明的变量作用域仅在 if 之内。
package main import ( "fmt" "math" ) func main() { fmt.Println( pow(3, 2, 10), pow(3, 3, 20), ) } func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } // return v // 错误:undefined: v return lim }上述示例中的第16行中,语句v := math.Pow(x, n)会优先求值。然后再拿结果进行比较。
类比一下:Java中类似语法可以这样写:
int r; if ((r = Math.round(x) > 0) { return r; }在 if 的简短语句中声明的变量同样可以在任何对应的 else 块中使用。 例如,将上述示例中的pow函数改为:
func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } else { fmt.Printf("pow(%v, %v, %v)超出lim参数范围,结果将被截取为%v\n", x, n, lim, lim) } // return v // 错误:undefined: v return lim }在Go中,如果if语句之后没有进入下一个语句,则意味着该if控制体中最后一行是 break、continue、goto或者return(这里省略了非必须的else语句):
f, err := os.Open(name) if err != nil { return err } codeUsing(f)联想:在Java中,break、continue只能出现在循环体中,而goto是保留关键字。
下面是一种常见的情况,其中代码必须处理防止一系列错误。由于错误情况将以return语句结束,因此之后的代码不需要else语句。
f, err := os.Open(name) if err != nil { return err } d, err := f.Stat() if err != nil { f.Close() return err } codeUsing(f, d)类比一下:这种做法在Java和其他语言中也很常见,避免过多的if-else嵌套。
上一节中的最后一个示例演示了:=简短声明的工作原理。调用os.Open的声明:
f, err := os.Open(name)该语句声明了两个变量f和err。几行之后,调用f.Stat:
d, err := f.Stat()看起来好像是声明了d和err。但请注意,err出现在两个语句中。这种重复是合法的:err是由第一个语句声明的,但在第二个语句中仅是重新赋值而已。这意味着对f.Stat的调用使用上面声明的现有err变量,并只是给它一个新值。
在:=声明中,即使已经声明变量v,也可能再次出现变量v,前提是:
此声明与v的现有声明在同一范围内(如果v已在外部作用域中声明,当前声明将创建一个新变量)初始化中的相应的值可分配给v,并且声明中至少有一个其他变量是新声明的。这种特殊的特性纯粹是为了实用,能够简单的复用同一个变量,而且这种用法很常见。
值得注意的是,在Go中,函数参数和返回值的作用域范围与函数体相同,即使它们在大括号之外的词法上出现。
参考: https://golang.org/doc/effective_go.html#if https://golang.org/ref/spec#If_statements