本篇文章带大家学习一下golang,聊聊go语言基础中的流程控制,希望对大家有所帮助。
go语言基础之流程控制主要包括以下内容:
条件语句if条件语句switch条件语句select循环语句for循环语句range循环控制goto、break、continue【编程教程推荐:编程教学】
1. 条件语句ifgo语言中if条件判断的格式如下:
if 表达式1 { 分支1} else if 表达式2 { 分支2} else{ 分支3}
前端的同学想必对js相对熟悉,相对于js来说,go表达式去掉了括号(),但同时给了一些约束,与if匹配的左括号{必须与if和表达式放在同一行,{放在其他位置会触发编译错误。 同理,与else匹配的{也必须与else写在同一行,else也必须与上一个if或else if右边的大括号在同一行。
x := 0// if x > 10 // error: missing condition in if statement// {// }if n := "abc"; x > 0 { // 初始化语句未必就是定义变量, 如 println("init") 也是可以的。 println(n[2])} else if x < 0 { // 注意 else if 和 else 左大括号位置。 println(n[1])} else { println(n[0])} *不支持三元操作符(三目运算符) "a > b ? a : b"。 package mainimport "fmt"func main() { /* 定义局部变量 */ var a int = 10 /* 使用 if 语句判断布尔表达式 */ if a < 20 { /* 如果条件为 true 则执行以下语句 */ fmt.printf("a 小于 20\n" ) } fmt.printf("a 的值为 : %d\n", a)}以上代码执行结果为:a 小于 20a 的值为 : 10
2. 条件语句switchswitch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上直下逐一测试,直到匹配为止。 golang switch 分支表达式可以是任意类型,不限于常量。可省略 break,默认自动终止。
package mainimport "fmt"func main() { /* 定义局部变量 */ var grade string = "b" var marks int = 90 switch marks { case 90: grade = "a" case 80: grade = "b" case 50,60,70 : grade = "c" default: grade = "d" } switch { case grade == "a" : fmt.printf("优秀!\n" ) case grade == "b", grade == "c" : fmt.printf("良好\n" ) case grade == "d" : fmt.printf("及格\n" ) case grade == "f": fmt.printf("不及格\n" ) default: fmt.printf("差\n" ) } fmt.printf("你的等级是 %s\n", grade )}以上代码执行结果为:优秀!你的等级是 a
3. 条件语句selectselect 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
select 是go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。 select 随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。
以下描述了 select 语句的语法:
每个case都必须是一个通信 所有channel表达式都会被求值 所有被发送的表达式都会被求值 如果任意某个通信可以进行,它就执行;其他被忽略。 如果有多个case都可以运行,select会随机公平地选出一个执行。其他不会执行。 否则: 如果有default子句,则执行该语句。 如果没有default字句,select将阻塞,直到某个通信可以运行;go不会重新对channel或值进行求值。
package mainimport "fmt"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): // same as: i3, ok := <-c3 if ok { fmt.printf("received ", i3, " from c3\n") } else { fmt.printf("c3 is closed\n") } default: fmt.printf("no communication\n") } }以上代码执行结果为: no communication
select可以监听channel的数据流动
select的用法与switch语法非常类似,由select开始的一个新的选择块,每个选择条件由case语句来描述
与switch语句可以选择任何使用相等比较的条件相比,select有比较多的限制,其中最大的一条限制就是每个case语句里必须是一个io操作
select { //不停的在这里检测 case <-chanl : //检测有没有数据可以读 //如果chanl成功读取到数据,则进行该case处理语句 case chan2 <- 1 : //检测有没有可以写 //如果成功向chan2写入数据,则进行该case处理语句 //假如没有default,那么在以上两个条件都不成立的情况下,就会在此阻塞//一般default会不写在里面,select中的default子句总是可运行的,因为会很消耗cpu资源 default: //如果以上都没有符合条件,那么则进行default处理流程 }
在一个select语句中,go会按顺序从头到尾评估每一个发送和接收的语句。
如果其中的任意一个语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。 如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况: ①如果给出了default语句,那么就会执行default的流程,同时程序的执行会从select语句后的语句中恢复。 ②如果没有default语句,那么select语句将被阻塞,直到至少有一个case可以进行下去。
典型用法-超时判断//比如在下面的场景中,使用全局reschan来接受response,如果时间超过3s,reschan中还没有数据返回,则第二条case将执行var reschan = make(chan int)// do requestfunc test() { select { case data := <-reschan: dodata(data) case <-time.after(time.second * 3): fmt.println("request time out") }}func dodata(data int) { //...}
4. 循环语句for和if一样,相对于js,go语言的for循环也去掉了括号(),其他并没有太大的区别。
package mainimport "fmt"func main() { var b int = 15 var a int numbers := [6]int{1, 2, 3, 5} /* for 循环 */ for a := 0; a < 10; a++ { fmt.printf("a 的值为: %d\n", a) } for a < b { a++ fmt.printf("a 的值为: %d\n", a) } for i,x:= range numbers { fmt.printf("第 %d 位 x 的值 = %d\n", i,x) } }以上实例运行输出结果为: a 的值为: 0 a 的值为: 1 a 的值为: 2 a 的值为: 3 a 的值为: 4 a 的值为: 5 a 的值为: 6 a 的值为: 7 a 的值为: 8 a 的值为: 9 a 的值为: 1 a 的值为: 2 a 的值为: 3 a 的值为: 4 a 的值为: 5 a 的值为: 6 a 的值为: 7 a 的值为: 8 a 的值为: 9 a 的值为: 10 a 的值为: 11 a 的值为: 12 a 的值为: 13 a 的值为: 14 a 的值为: 15 第 0 位 x 的值 = 1 第 1 位 x 的值 = 2 第 2 位 x 的值 = 3 第 3 位 x 的值 = 5 第 4 位 x 的值 = 0 第 5 位 x 的值 = 0
5. 循环语句rangegolang range类似迭代器操作,返回 (索引, 值) 或 (键, 值)。
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldmap { newmap[key] = value}
package mainfunc main() { s := "abc" // 忽略 2nd value,支持 string/array/slice/map。 for i := range s { println(s[i]) } // 忽略 index。 for _, c := range s { println(c) } // 忽略全部返回值,仅迭代。 for range s { } m := map[string]int{"a": 1, "b": 2} // 返回 (key, value)。 for k, v := range m { println(k, v) }}输出结果: 97 98 99 97 98 99 a 1 b 2
for 和 for range有什么区别?
主要是使用场景不同
for可以遍历array和slice,遍历key为整型递增的map,遍历string
for range可以完成所有for可以做的事情,却能做到for不能做的,包括遍历key为string类型的map并同时获取key和value,遍历channel
6. 循环控制goto、break、continue循环控制语句
循环控制语句可以控制循环体内语句的执行过程。
go 语言支持以下几种循环控制语句:
goto、break、continue 1.三个语句都可以配合标签(label)使用 2.标签名区分大小写,定以后若不使用会造成编译错误 3.continue、break配合标签(label)可用于多层循环跳出 4.goto是调整执行位置,与continue、break配合标签(label)的结果并不相同
break(跳出循环):continue(继续下次循环)break语句可以结束for、switch和select的代码块。break语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的for、switch和 select的代码块上。
continue(继续下次循环):continue语句可以结束当前循环,开始下一次的循环迭代过程,仅限在for循环内使用。在 continue语句后添加标签时,表示开始标签对应的循环
goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。go语言中使用goto语句能简化一些代码的实现过程。 例如双层嵌套的for循环要退出时:
func gotodemo1() { var breakflag bool for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { if j == 2 { // 设置退出标签 breakflag = true break } fmt.printf("%v-%v\n", i, j) } // 外层for循环判断 if breakflag { break } }}
使用goto语句能简化代码:
func gotodemo2() { for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { if j == 2 { // 设置退出标签 goto breaktag } fmt.printf("%v-%v\n", i, j) } } return // 标签breaktag: fmt.println("结束for循环")}
结束:再次提醒,需要进技术交流群的同学,可以加我微信fangdongdong_25,需要进前端工程师交流群的备注“前端”,需要进go后端交流群的备注“go后端”
【相关推荐:go视频教程】
以上就是一文浅析golang中的流程控制的详细内容。