一、踩得坑

	for {
time.Sleep(p.Cfg.WatchInterval)
select {
case <-ctx.Done():
return default:
err := p.watchSomeThing(ctx)
if err != nil {
p.Error(zap.Error(errors.Wrap(err, "watch something")))
//continue
break //TODO:临时修改
}
}
}

最近项目中有上面一段代码,本来是为了临时修改在出错的时候能够退出最外层的for循环,简单的使用break,结果实际测试的时候仍然不起作用。后面发现其实是自己对break的用法理解还是不够透彻。

二、break的使用

1、break用于for循环

/* for 循环 */
for a < 20 {
fmt.Printf("a 的值为 : %d\n", a);
a++;
if a > 15 {
/* 使用 break 语句跳出循环 */
break;
}
}

例如上面的一段代码,即利用break跳出一个for循环。

2、 break用于select

    select {
case <-ch:
fmt.Println("This case is selected.")
break //The following statement in this case will not execute.
fmt.Println("After break statement")
default:
fmt.Println("This is the default case.")
}

例如上面一段代码,即利用break跳出一个select循环

3、break用于嵌套循环

	stopLable:
for {
time.Sleep(p.Cfg.WatchInterval)
select {
case <-ctx.Done():
return default:
err := p.watchSomeThing(ctx)
if err != nil {
p.Error(zap.Error(errors.Wrap(err, "watch something")))
//continue
break stopLable//TODO:临时修改
}
}
}

在 switch 或 select 语句中,break语句的作用结果是跳过整个代码块,执行后续的代码。但是嵌套循环时,只会跳出最内层的循环,最外层的for循环还是一直在跑。要想跳出最外层的循环可以在 break 后指定标签。用标签决定哪个循环被终止。

4、break label 、 goto label 、continue label

break label 和 goto label都能在循环中跳出循环,但是又有些不同之处。

  • break label:跳转标签(label)必须放在循环语句for前面,并且在break label跳出循环不再执行for循环里的代码。且break标签只能用于for循环
package main

import "fmt"

func main() {
outLable:
for i:=0; i< 5; i++{
fmt.Printf("外层:第%d次外层循环\n", i)
for j:=0; j< 5; j++ {
fmt.Printf("内层:第%d次内层循环\n", j)
break outLable
}
fmt.Printf("外层:没有跳过第%d次循环\n", i)
}
}

输出:

外层:第0次外层循环
内层:第0次内层循环
  • continue label: :跳转标签(label)必须放在循环语句for前面,跳出循环后则将继续执行lable后面的代码,即开始下一次外层循环
package main

import "fmt"

func main() {
outLable:
for i:=0; i< 5; i++{
fmt.Printf("外层:第%d次外层循环\n", i)
for j:=0; j< 5; j++ {
fmt.Printf("内层:第%d次内层循环\n", j)
continue outLable
}
fmt.Printf("外层:没有跳过第%d次循环\n", i)
}
}

输出:

外层:第0次外层循环
内层:第0次内层循环
外层:第1次外层循环
内层:第0次内层循环
外层:第2次外层循环
内层:第0次内层循环
外层:第3次外层循环
内层:第0次内层循环
外层:第4次外层循环
内层:第0次内层循环
  • goto lable:既可以定义在for循环前面,也可以定义在for循环后面,当跳转到标签地方时,继续执行标签下面的代码。
package main

import "fmt"

func main() {
outLable:
for i:=0; i< 5; i++{
fmt.Printf("外层:第%d次外层循环\n", i)
for j:=0; j< 5; j++ {
fmt.Printf("内层:第%d次内层循环\n", j)
goto outLable
}
fmt.Printf("外层:没有跳过第%d次循环\n", i)
}
}

输出:

外层:第0次外层循环
内层:第0次内层循环
外层:第0次外层循环
内层:第0次内层循环
外层:第0次外层循环
内层:第0次内层循环
外层:第0次外层循环
内层:第0次内层循环
外层:第0次外层循环
内层:第0次内层循环
......

5、官方解释

Break statements

A “break” statement terminates execution of the innermost “for”, “switch”, or “select” statement within the same function.

BreakStmt = “break” [ Label ] .

If there is a label, it must be that of an enclosing “for”, “switch”, or “select” statement, and that is the one whose execution terminates.

OuterLoop:
for i = 0; i < n; i++ {
for j = 0; j < m; j++ {
switch a[i][j] {
case nil:
state = Error
break OuterLoop
case item:
state = Found
break OuterLoop
}
}
}

Continue statements

A “continue” statement begins the next iteration of the innermost “for” loop at its post statement. The “for” loop must be within the same function.

ContinueStmt = “continue” [ Label ] .

If there is a label, it must be that of an enclosing “for” statement, and that is the one whose execution advances.

RowLoop:
for y, row := range rows {
for x, data := range row {
if data == endOfRow {
continue RowLoop
}
row[x] = data + bias(x, y)
}
}

Goto statements

A “goto” statement transfers control to the statement with the corresponding label within the same function.

GotoStmt = “goto” Label .

goto Error

Executing the “goto” statement must not cause any variables to come into scope that were not already in scope at the point of the goto. For instance, this example:

	goto L  // BAD
v := 3
L:
is erroneous because the jump to label L skips the creation of v.

A “goto” statement outside a block cannot jump to a label inside that block. For instance, this example:

if n%2 == 1 {
goto L1
}
for n > 0 {
f()
n--
L1:
f()
n--
}

is erroneous because the label L1 is inside the “for” statement’s block but the goto is not.

参考文章

1、In Go, does a break statement break from a switch/select?

2、https://golang.org/ref/spec#Break_statements

3、Go语言之continue/break label(五)

最新文章

  1. Xcode8中处理打印日志的配置
  2. SSI指令
  3. 【管理心得之三十八】如果“Q”不是高富帅,也吸引不了白富美“A”
  4. C#----格式化字符串的操作
  5. 2016年10月18日 星期二 --出埃及记 Exodus 19:2
  6. #你好Unity3D#Project脚本执行双击资源操作
  7. 一点关于this的理解
  8. ASP.NET MVC 4.0 学习4-Code First
  9. _itemFailedToPlayToEnd: { kind = 1; new = 2; old = 0; }
  10. mybatis以序列周期,同样处理的这个问题的价值
  11. JS原生javascript可以直接写id名来选取元素
  12. spring jar包
  13. Object 与 T的差别 导致swagger 的model 显示的数据为空
  14. 小程序里let和var以及const区别
  15. 解决 ora-28001 密码过期的处理办法
  16. VS中C#的快捷键
  17. Oracle substr() instr() 用法
  18. Spring Cloud Zuul的一个坑
  19. libXext.so.6: cannot open shared object file:
  20. 科学计算法帮助类MathUtils

热门文章

  1. Linux JDK 安装与配置
  2. beacon帧字段结构最全总结(二)——HT字段总结
  3. 小白学 Python(24):Excel 基础操作(下)
  4. tensorflow中的学习率调整策略
  5. [LC]876题 Middle of the Linked List (链表的中间结点)(链表)
  6. SVN积极拒绝解决办法
  7. Thrift总结(四)Thrift实现双向通信
  8. win10 visual studio 2017环境中安装CUDA8
  9. [第二章]了解storm
  10. ArcGIS API For Javascript:新增热力图层的方法