if
else-if
分支的数量是没有限制的,但为了可读性,尽量不要太多。
if condition {
// do something
}
if condition {
// do something
} else {
// do something
}
if condition1 {
// do something
} else if condition2 {
// do something else
} else {
// catch-all or default
}
复制代码
注意:else
与前面的 }
必须在同一行:
if x{
}
else { // 无效的
}
复制代码
switch
switch
的结构相比其它语言更加灵活,可以接受任意形式的表达式
switch var1 {
case val1:
...
case val2:
...
default:
...
}
switch var1 {
case val1, val2, val3:
...
case val4:
...
default:
...
}
复制代码
- 每一个
case
分支都是唯一的,从上至下逐一测试,直到匹配为止。 - 一旦成功地匹配到某个分支,执行完相应代码后就会退出整个
switch
代码块。如果还想执行后续代码,可以使用fallthrough
达到目的。 - 同时测试多个可能符合条件的值,使用逗号分割它们,例如:
case val1, val2, val3
- 在
case ...:
语句之后,不需要使用花括号,可以在分支中进行任意形式的编码。当代码块只有一行时,可以直接放置在case
语句之后 val1
、val2
、val3
和val4
必须是相同的类型,或者最终结果为相同类型的表达式default
分支是可选的,可以出现在任何顺序,但最好将它放在最后
省略判断值
可以不提供任何被判断的值(实际上默认为判断是否为 true
),然后在每个 case
分支中进行测试不同的条件。当任一分支的测试结果为 true
时,该分支的代码会被执行。这看起来非常像链式的 if-else
语句,但是在测试条件非常多的情况下,提供了可读性更好的书写方式。
switch {
case condition1:
...
case condition2:
...
default:
...
}
switch {
case i < 0:
f1()
case i == 0:
f2()
case i > 0:
f3()
}
复制代码
初始化语句
switch
语句也可以包含一个初始化语句,这种形式可以非常优雅地进行条件判断
switch initialization {
case val1:
...
case val2:
...
default:
...
}
switch result := calculate(); {
case result < 0:
...
case result > 0:
...
default:
// 0
}
// 在下面这个代码片段中,变量 a 和 b 被平行初始化,然后作为判断条件:
switch a, b := x[i], y[j]; {
case a < b: t = -1
case a == b: t = 0
case a > b: t = 1
}
复制代码
fallthrough
如果在执行完每个分支的代码后,还希望继续执行后续分支的代码,可以使用 fallthrough
关键字来达到目的。
func main() {
i := 0
switch i {
case 0: fallthrough
case 1:
fmt.Println("111")
fallthrough
case 2:
fmt.Println("222")
case 3:
fmt.Println("333")
default:
fmt.Println("default")
}
}
复制代码
type-switch
switc
h 语句还可以被用于 type-switch
来判断某个 interface
变量中实际存储的变量类型。
v := 11
switch i := interface{}(v).(type) {
case int, int8, int16, int32, int64:
fmt.Printf("A signed integer: %d. The type is %T. \n", i, i)
case uint, uint8, uint16, uint32, uint64:
fmt.Printf("A unsigned integer: %d. The type is %T. \n", i, i)
default:
fmt.Println("Unknown!")
}
复制代码
for
for 初始化语句; 条件语句; 修饰语句 {}
复制代码
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
// 错误的代码
for (i := 0; i < 10; i++) {
fmt.Print(i, " ")
}
// 使用多个计数器
for i, j := 0, N; i < j; i, j = i+1, j-1 {}
// 嵌套
for i:=0; i<5; i++ {
for j:=0; j<10; j++ {
println(j)
}
}
复制代码
for
经常和 range
搭配使用
select
select
语句属于条件分支流程控制方法,不过它只能用于通道(后面再介绍)。它可以包含若干条 case
语句,case
关键字只能后跟用于通道的发送操作的表达式以及接收操作的表达式或语句。
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
select {
case e1 := <-ch1:
fmt.Printf("1th case is selected. e1=%v.\n", e1)
case e2 := <-ch2:
fmt.Printf("2th case is selected. e2=%v.\n", e2)
default:
fmt.Println("No data!")
}
复制代码
break
语句也可以被包含在 select
语句中的 case
语句中。它的作用是立即结束当前的 select
语句的执行,不论其所属的 case
语句中是否还有未被执行的语句。
扫描二维码关注公众号,回复: 5465014 查看本文章
break/continue
break
用来跳出循环,用于任何形式的 for
循环,但在 switch
或 select
语句中,break
语句的作用结果是跳过整个代码块,执行后续的代码。
break
的作用范围为该语句出现后的最内部的结构,也就是嵌套的循环体中,break
只会退出最内层的循环
continue
只能被用于 for
循环中,作用是忽略剩余的循环体而直接进入下一次循环的过程,但不是无条件执行下一次循环,执行之前依旧需要满足循环的判断条件。
label/goto
for
、switch
或 select
语句都可以配合标签 label
形式的标识符使用,即某一行第一个以冒号(:
)结尾的单词(gofmt
会将后续代码自动移至下一行)。
标签的名称是大小写敏感的,为了提升可读性,一般建议使用全部大写字母。
func main() {
AAA:
for i := 1; i < 3; i++ {
fmt.Println("a", i)
for j := 1; j < 5; j++ {
fmt.Println("b", j)
if j == 2 {
continue AAA
}
}
}
}
// 输出:
a 1
b 1
b 2
a 2
b 1
b 2
复制代码
j==3
、j==4
时没有输出,因为跳到了 i
的下一次循环。如果将 continue
改成 break
,会直接退出外层循环。
使用 goto 语句和标签配合使用来模拟循环
func main() {
i := 0
AAA:
fmt.Println(i)
i++
if i == 5 {
return
}
goto AAA
}
复制代码
注意:使用标签和 goto
语句是不被鼓励的,它们会很快导致非常糟糕的程序设计,而且总有更加可读的替代方案来实现相同的需求。
如果您必须使用 goto
,应当只使用正序的标签(标签位于 goto
语句之后),但注意标签和 goto
语句之间不能出现定义新变量的语句,否则会导致编译失败。