🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ### Switch 语句 ***** #### 提供背判断的值 ``` switch var1 { case val1: ... case val2: ... default: ... } ``` 变量 var1 可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式。前花括号 { 必须和 switch 关键字在同一行。 **不需要特别使用 break 语句来表示结束。** 如果在执行完每个分支的代码后,还希望**继续执行后续分支的代码**,可以使用 **fallthrough** 关键字来达到目的。 ` ` #### 不提供被判断的值 ``` switch { case condition1: ... case condition2: ... default: ... } ``` #### 包含初始化语句: ``` switch initialization { case val1: ... case val2: ... default: ... } ``` ` ` ### Select控制 ***** select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。 >select中的case语句必须是一个channel操作 select中的default子句总是可运行的。 * 如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。 * 如果没有可运行的case语句,且有default语句,那么就会执行default的动作。 * 如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行。 ``` package main import ( "fmt" "time" ) func main() { var c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: fmt.Printf("received ", i1, " from c1\n") case c2 <- i2: fmt.Printf("sent ", i2, " to c2\n") case i3, ok := (<-c3): if ok { fmt.Printf("received ", i3, " from c3\n") } else { fmt.Printf("c3 is closed\n") } case <-time.After(time.Second * 3): //超时退出 fmt.Println("request time out") } } // 输出:request time out ``` ` ` ### For循环 ***** 最简单的基于计数器的迭代,基本形式为: ``` for 初始化语句; 条件语句; 修饰语句 {} ``` 这三部分组成的循环的头部,它们之间使用分号 ; 相隔,但并不需要括号 () 将它们括起来。 您还可以在循环中同时使用多个计数器: ``` for i, j := 0, N; i < j; i, j = i+1, j-1 {} ``` 这得益于 Go 语言具有的平行赋值的特性,for 结构的第二种形式是没有头部的条件判断迭代(类似其它语言中的 while 循环),基本形式为:for 条件语句 {}。 ` ` 条件语句是可以被省略的,如 i:=0; ; i++ 或 for { } 或 for ;; { }(;; 会在使用 Gofmt 时被移除):这些循环的本质就是无限循环。 最后一个形式也可以被改写为 for true { },但一般情况下都会直接写 **for { }**。 ` ` ### for-range结构 ***** 这是 Go 特有的一种的迭代结构,您会发现它在许多情况下都非常有用。它可以迭代任何一个集合(包括数组和 map),同时可以获得每次迭代所对应的索引。一般形式为: ``` for ix, val := range coll { } ``` 要注意的是,val 始终为集合中对应索引的值拷贝,因此它一般只具有只读性质,对它所做的任何修改都不会影响到集合中原有的值(注:如果 val 为指针,则会产生指针的拷贝,依旧可以修改集合中的原值)。 ` ` ### **break** ***** 一个 break 的作用范围为该语句出现后的最内部的结构,它可以被用于任何形式的 for 循环(计数器、条件判断等)。 但在 switch 或 select 语句中,break 语句的作用结果是跳过整个代码块,执行后续的代码。 ` ` ### **continue** ` ` 关键字 continue 忽略剩余的循环体而直接进入下一次循环的过程,但不是无条件执行下一次循环,执行之前依旧需要满足循环的判断条件。 关键字 continue 只能被用于 for 循环中。 ` ` ### **label** ***** 在Golang中能使用`Label`的有`goto`,`break`,`continue`. 这篇文章就介绍下Golang中`Label`使用和注意点. 注意点: 1. `Label`在continue, break中是`可选的`, 但是在`goto`中是`必须的` 2. 作用范围: 定义`Label`的函数体内. 3. `Label`可以声明在函数体的任何位置, 不管`Label`声明在`调用点`的前面还是后面. ` ` #### goto 1. `Label`在`goto`是必须的 ``` package main import ( "fmt" ) func main() { fmt.Println(1) goto End //goto 10: syntax error: unexpected . at end of statement fmt.Println(2) End: fmt.Println(3) } ``` 2.`Label`可以声明在函数体的任何地方 3.`Label`的作用范围是在函数体中 4.`Label`在嵌套函数(闭包)是不可用的. 不管是在`闭包里`调用`闭包外`的Label, 还是在`闭包外`调用`闭包里`的Label: ``` package main import ( "fmt" ) func main() { fmt.Println(1) func() { fmt.Println("Nested function") goto End }() End: fmt.Println(2) } ``` 5.不能重复定义`Label` 6.`Label`和变量名是`不冲突的`, 可以定义一个名为`x`的变量和名为`x`的Label(不过不建议这么用, 这么写会被人骂的); 而且`Label`是区分大小写的. 7.变量的声明必须在`goto`之前.因为任何变量的声明都不能被跳过. ` ` #### break(不带label) `break`一般用来跳出`最近`一层的`switch`和`for`, 注意不能用在`select`上 1.单层循环 ``` package main import ( "fmt" ) func main() { for i := 0; i < 10; i++ { fmt.Println(i) if i == 3 { break } } } //out 0 1 2 3 ``` 2.双层循环 ``` package main import ( "fmt" ) func main() { for i := 0; i < 3; i++ { for j := 0; j < 5; j++ { fmt.Println("i:", i, ",j:", j) if j == 2 { break } } } } //Output i: 0 ,j: 0 i: 0 ,j: 1 i: 0 ,j: 2 i: 1 ,j: 0 i: 1 ,j: 1 i: 1 ,j: 2 i: 2 ,j: 0 i: 2 ,j: 1 i: 2 ,j: 2 ``` 从这个例子可以看出`break`只能跳出最近`for` 3.对于`c/c++`来说,`switch/case`一般都是配合`break`来使用的.但是在`golang`中`switch/case`不需要`break`就能够实现和`c/c++`一样的效果. 4.`break`在函数里是不起作用的, 不能传递出来. ` ` #### break(Label) + continue ``` func main() { LABEL_1: for i := 0; i < 10; i++ { if i == 8 { goto END } if i%2 == 0 { for { continue LABEL_1 } } index := 0 LABEL_2: for { index++ fmt.Println("index ", index) break LABEL_2 } fmt.Println("i ", i) } fmt.Println("after loop") END: fmt.Println("end") } ``` break和continue的label必须写在代码块的前面 其中,break label 将直接跳出循环,即不再执行label所标记的循环 而continue label 则将继续执行循环,即开始下一次循环 ``` index 1 i 1 index 1 i 3 index 1 i 5 index 1 i 7 end ```