Go——控制结构(if、switch、for、Lable、goto、break)

控制结构

现代计算机存储结构无论“普林斯顿结构”,还是“哈佛结构”,程序指令都是线性地存放在存储器上。程序执行从本质上来说就是两种模式:顺序和跳转。

·顺序就是按照程序指令在存储器上的存放顺序逐条执行。
跳转就是遇到跳转指令就跳转到某处继续线性执行。
Go是一门高级语言,其源程序虽然经过了高度的抽象并封装了很多语法糖,但还是跳不出这个模式(这里暂时不考虑goroutine引入并发后的执行视图变化)。

顺序在Go里面体现在从main函数开始逐条向下执行,就像我们的程序源代码顺序一样;跳转在Go里面体现为多个语法糖,包括goto语句和函数调用、分支(if、switch、select)、循环(for)等。

跳转分为两种:一种是无条件跳转,比如函数调用和goto语句;一种是有条件的跳转,比如分支和循环。

1、 if语句

  • if后面的条件判断子句不需要用小括号括起来。
  • {必须放在行尾,和if或if else放在一行。
  • if后面可以带一个简单的初始化语句,并以分号分割,该简单语句声明的变量的作用域是整个f语句块,包括后面的else if和else分支。
  • Go语言没有条件运算符(a>b?a:b),这也符合Go的设计哲学,只提供一种方法做事情。
  • if分支语句遇到return后直接返回,遇到break则跳过break下方的if语句块。

简单示例:

if x <= y {
	return y 
} else {
	return x 
}

一个完整的if else语句示例:

if x := f(); x < y { // 初始化语句中的声明变量x
	return x 
} else if x > z { //x在else if里面一样可以被访问
	return z 
} else {
	return y
}

最佳实践:

  • 尽量减少条件语句的复杂度,如果条件语句太多、太复杂,则建议放到函数里面封装起来。
  • 尽量减少if语句的嵌套层次,通过重构让代码变得扁平,便于阅读:
if err, file :== os.Open("xxxx"); err == nil {
	defer file.Close()
	//do something
} else {
	return nil, err 
}

改写后的代码:

err, file := os.Open("xxxx")
if err != nil {
	return nil, err 
} 
defer file.Close()
//do something

2、switch语句

switch语句会根据传入的参数检测并执行复合条件的分支:

  • switch和if语句一样,switch后面可以带一个可选的简单的初始化语句。
  • switch后面的表达式也是可选的,如果没有表达式,则case子句是一个布尔表达式,而不是一个值,此时就相当于多重if else语句。
  • switch条件表达式的值不像C语言那样必须限制为整数,可以是任意支持相等比较运算的类型变量。
  • 通过fallthough语句来强制执行下一个case子句(不再判断下一个case子句的条件是否满足)。
  • switch支持default语句,当所有的case分支都不符合时,执行default语句,并且default语句可以放到任意位置,并不影响switch的判断逻辑。
  • switch和.(type)结合可以进行类型的查询。
switch i := "y"; i { //switch后面可以带上一个初始化语句
case "y", "Y": //多个case值使用逗号分隔
	fmt.Println("yes") //yes
	fallthrough        //fallthrough会跳过接下来的case表达式直接执行下一个case语句
case "n", "N":
	fmt.Println("no") //no
}

score := 85
grade := ' '
if score >= 90 {
	grade = 'A'
} else if score >= 80 {
	grade = 'B'
} else if score >= 70 {
	grade = 'C'
} else if score >= 60 {
	grade = 'D'
} else {
	grade = 'E'
}

fmt.Printf("%c\n", grade) //B

//上面的if else可以改写为下面的switch语句
switch {
case score >= 90:
	grade = 'A'
case score >= 80:
	grade = 'B'
case score >= 70:
	grade = 'C'
case score >= 60:
	grade = 'D'
default:
	grade = 'F'
}
fmt.Printf("grade=%c\n", grade)

3、for语句

Go语言仅支持一种循环语句,即for语句,同样遵循Go的设计哲学,只提供一种方法做事情,把事情做好。

Go对应C循环的三种场景如下:

  • 类似C里面的for循环
for init; condition; post { }
  • 类似C里面的while循环语句
for condition { }
  • 类似C里面的while(1)死循环语句
for { }

for还有一种用法,是对数组、切片、字符串、map和通道的访问,语法格式如下:

//访问map
for key, value := range map { }
for key := range map { }

//访问数组
for index, value := range arry { }
for index := range arry { }
for _, value := range arry { }

//访问切片
for index, value := range slice { }
for index := range slice { }
for _, value := range slice { }

//访问通道
for value := range channel { }

4、标签和跳转

4.1 标签

Go语言使用标签(Lable)来标识一个语句的位置,用于goto、break、continue语句的跳转,标签的语法是:

Lable: Statement
4.2 goto

goto语句用于函数的内部跳转,需要配合标签一起使用,具体的格式如下:

goto Lable
  • goto语句只能在函数内跳转。
  • goto语句不能跳过内部变量声明语句,这些变量在goto语句的标签语句处又是可见的。
goto L //Bad,跳过v:=3这条语句是不允许的
v := 3
L:
  • goto语句只能跳到同级作用域或者上层作用域内,不能跳到内部作用域内。
if n % 2 == 1 {
	goto L1
}
for n > 0 {
	f()
	n--
L1:
	f()
	n--
}
4.3 break

break用于函数内部跳出for、switch、select语句的执行,有两种使用格式:

  • 单独使用,用于跳出break当前所在的for、switch、select语句的执行。
  • 和标签一起使用,用于跳出标签所标识的for、switch、select语句的执行,可用于跳出多重循环,但标签和break必须在同一个函数内。例如:
L1:
	for i := 0; ; i++ {
		for j := 0; ; j++ {
			if i >= 5 {
				//跳出L1标签所在的for循环
				break L1
			}
			if j > 10 {
				//默认仅跳出离break最近的内层循环
				break
			}
		}
	}
4.4 continue

continue用于跳出for循环的本次迭代,跳到for循环的下一次迭代的post语句处执行,也有两种使用格式:

  • 单独使用,用于跳出continue当前所在的for循环的本次迭代。
  • 和标签一起使用,用于跳出标签所标识的for语句的本次迭代,但标签和continue必须在同一个函数内。例如:
L1:
	for i := 0; ; i++ {
		for j := 0; ; j++ {
			if i >= 5 {
				//跳到L1标签所在的for循环i++处执行
				continue L1
				//the following is not executed
			}
			if j > 10 {
				//默认仅跳到离break最近的内层循环j++处执行
				continue 
			}
		}
	}
4.5 return和函数调用

return语句也能引发控制流程的跳转,用于函数和方法的退出。函数和方法的调用也能引发控制流的跳转。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值