Go 语言编程 — 逻辑控制语句
目录
文章目录
- 目录
- 条件判断
- if/else 语句
- switch 语句
- fallthrough 语句
- type-switch 语句
- select(开关)语句
- 循环
- for 循环语句
- For-each range 循环语句
- 循环控制语句
- break 语句
- continue 语句
- goto 语句
条件判断
if/else 语句
示例:
package mainimport "fmt"func main() {var a int = 100if a > 0 && a < 20 {fmt.Printf("a 小于 20\n")} else {fmt.Printf("a 不小于 20\n")}fmt.Printf("a 的值为 : %d\n", a)
}
可见,Golang 中的条件表达式不需要使用 “()” 括起来。
另外,Golang 支持在判断时可以同时执行定义赋值等操作:
if err = af.Run(parenCtx, cfgPath); err != nil {log.Errf("AF finished with error: %v", err)
}
相当于先执行其他语句(通常是赋值语句),然后再执行条件判断语句。
注意:Golang 中 if 的条件判断语句是不可以仅仅编写赋值语句的:
if a = true {}
这样的代码在 C 语言中可以编译过,但 Golang 的编译器会报错。
switch 语句
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
与 C 语言不同,Golang 中的 switch 匹配项后面也不需要再加 break 语句。switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case。如果我们需要执行后面的 case,可以使用 fallthrough 语句。
格式:
switch var1 {case val1:...case val2:...default:...
}
其中,变量 var1 可以是任何类型,而 val1 和 val2 则是同类型的任意值,类型不被局限于常量或整数,但必须是相同的类型。或者最终结果为相同类型的表达式。如果希望通过布尔数据类型来进行判定,则 switch 关键字后不需要紧跟条件表达式。
同时,还可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3
。
示例:
package mainimport "fmt"func main() {var grade stringvar marks int = 90/* 带有表达式的 switch 语句,表达式的结果与 case 进行匹配。 */switch marks {case 90:grade = "A"case 80:grade = "B"case 50, 60, 70:grade = "C"default:grade = "D"}fmt.Printf("你的等级是 %s\n", grade);/* 不带有表达式的 switch 语句,由 case 语句表达式判断是否为 True。 */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");}
}
结果:
你的等级是 A
优秀!
fallthrough 语句
在 switch 中使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true,而是直接执行。
示例:
package mainimport "fmt"func main() {switch {case false:fmt.Println("1、case 条件语句为 false")fallthroughcase true:fmt.Println("2、case 条件语句为 true")fallthroughcase false:fmt.Println("3、case 条件语句为 false")fallthroughcase true:fmt.Println("4、case 条件语句为 true")case false:fmt.Println("5、case 条件语句为 false")fallthroughdefault:fmt.Println("6、默认 case")}
}
结果:
2、case 条件语句为 true
3、case 条件语句为 false
4、case 条件语句为 true
type-switch 语句
Golang 中,还可以使用 type-switch 来判断某个 interface(接口)变量中实际存储的变量类型。
格式:
switch x.(type) {case type:statements/* 可以定义任意个数的 case */default:statements
}
示例:
package mainimport "fmt"func main() {/* 定义一个接口类型变量。 */var itf interface{}/* 判断接口类型变量存储的数值的类型。 */switch i := itf.(type) {case nil:fmt.Printf("interface 的类型: %T", i)case bool:fmt.Printf("interface 是 bool 型")case int:fmt.Printf("interface 是 int 型")case float64:fmt.Printf("interface 是 float64 型")case func(int) float64:fmt.Printf("interface 是 func(int) 型")default:fmt.Printf("未知类型")}
}
结果:
interface 的类型: <nil>
select(开关)语句
select 语句类似于用于通信的 switch 语句。区别在于 select 语句是专为 channel(通道)而设计的,每个 case 必须是一个通信操作,要么是发送(ch <-
)要么是接收(<- ch
)。
- 每个 case 都必须是一个通信操作(communication clause)。
- 所有 channel 表达式都会被求值。
- 如果任意某个通信可以进行,它就执行,其他则被忽略。
- 如果有多个 case 可以运行,select 会随机公平地选出一个执行。其他则被忽略。
- 如果没有 case 可以运行:
- 如果有 default 子句,则执行该语句。
- 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Golang 不会重新对 channel 或值进行求值。
格式:
select {case communication clause:statements/* 你可以定义任意数量的 case */default:statements
}
示例:
package mainimport "fmt"func main() {var c1, c2, c3 chan intvar i1, i2 intselect {case i1 = <-c1:fmt.Println("received ", i1, " from c1")case c2<- i2:fmt.Println("sent ", i2, " to c2")case i3, ok := (<-c3):if ok {fmt.Println("received ", i3, " from c3")} else {fmt.Println("c3 is closed")}default:fmt.Println("no communication")}
}
因为 select 会循环检测所有 case 的表达式,所以 select 语句本身不需要表达式,这一点与 switch 语句也不通。select 语句中,如果有满足的 case 则执行并退出,否则一直循环检测。
package mainimport ("fmt""time"
)func test_channel(ch chan int, stop_ch chan bool) {var i int = 10/* 每个 1s 向 ch 通道发送一次整型数据。 */for j := 0; j < 10; j++ {ch<- itime.Sleep(time.Second)}stop_ch<- true
}func main() {/* 初始化通道类型变量。 */ch := make(chan int)stop_ch := make(chan bool)go test_channel(ch, stop_ch)for {select {/* 当 ch 通道接收到变量时,会随机选择 case a 或 b 执行。 */case a := <-ch:fmt.Println("Recvice a: ", a)case b := <-ch:fmt.Println("Receive b: ", b)case _ = <-stop_ch:goto end}}end:
}
结果:
Receive b: 10
Recvice a: 10
Recvice a: 10
Recvice a: 10
Receive b: 10
Recvice a: 10
Receive b: 10
Receive b: 10
Recvice a: 10
Receive b: 10
注意:如果没有初始化 channel 类型变量就对其进行发送、接收操作的话,会触发错误:fatal error: all goroutines are asleep - deadlock。·
循环
for 循环语句
Golang 仅支持 for 循环,执行过程如下:
- 先对 init 赋初值;
- 判别 init 是否满足 condition 条件,若其值为真,则执行循环体内语句,然后执行 post。进入第二次循环,再判别 condition;
- 否则判断 condition 的值为假,不满足条件,就终止 for 循环,执行循环体外语句。
Golang 的 for 循环具有 3 种形式。
- 和 C 语言的 for 一样,但循环控制语句不需要使用 “()” 括起来:
for init; condition; post { }
- init:一般为赋值表达式,给控制变量赋初值;
- condition:关系表达式或逻辑表达式,循环控制条件;
- post:一般为赋值表达式,给控制变量增量或减量。
示例:计算 1 到 10 的数字之和
package mainimport "fmt"func main() {sum := 0for i := 0; i <= 10; i++ {sum += i}fmt.Println(sum)
}
- 和 C 语言的 while 循环一样,省略了 init 和 post:
for condition { }
示例:
package mainimport "fmt"func main() {sum := 1for sum <= 10 {sum += sum}fmt.Println(sum)
}
- 和 C 的
for (;;)
一样,省略 init、condition 和 post,执行无限循环:
for {}
示例:
package mainimport "fmt"func main() {sum := 0for {sum++ // 无限循环下去}fmt.Println(sum)
}
For-each range 循环语句
Golang 提供了 range(范围)关键字,用于 for 循环中迭代字符串(String)、数组(Array)、切片(Slice)、通道(Channel)或集合(Map)数据类型变量中所含有的元素。
- 字符串、数组、切片:迭代元素的索引和索引对应的值。与 Python 中的 enumerate() 函数类似。
- 集合:迭代 key/value 对。与 Python 中的 Dict.items() 成员方法类似。
- 通道:迭代通道接收的数据。
格式:
for key, value := range oldMap {newMap[key] = value
}
示例:
package mainimport "fmt"func main() {/* 定义字符串数组变量 */ arr := []string {"hello", "world"}for idx, str := range arr {fmt.Println(idx, str)}/* 定义数字数组变量 */ numbers := [6]int {1, 2, 3, 5}for idx, num := range numbers {fmt.Printf("第 %d 位 x 的值 = %d\n", idx, num)}
}
结果:
0 hello
1 world
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0
示例:
package mainimport "fmt"func main() {/* 定义 Map 类型变量。 */kvs := map[string]string {"a": "apple", "b": "banana"}for k, v := range kvs {fmt.Printf("%s: %s\n", k, v)}/* 迭代字符串时,第一个参数是字符的索引,第二个是字符的 rune(字符的字节编码)数值。 */for i, c := range "go" {fmt.Println(i, c)}
}
结果:
a: apple
b: banana
0 103
1 111
循环控制语句
break 语句
- 用于循环语句中跳出循环,并开始执行循环之后的语句。
- break 在 switch 语句中在执行一条 case 后跳出。
- 在多重循环中,可以用标号 label 标出想跳出的循环。
示例:
package mainimport "fmt"func main() {// 不使用 label 标记fmt.Println("---- break ----")for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)break}}// 使用 label 标记,常见于跳出嵌套循环。fmt.Println("---- break label ----")re:for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)break re}}
}
结果:
---- break ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
---- break label ----
i: 1
i2: 11
continue 语句
与 breck 不同,continue 不是跳出循环,而是跳过当前循环并执行下一次循环。所以,在 for 循环中,执行 continue 语句同样会触发 for 增量语句的执行。
在多重循环中,同样可以用标号 label 标出想 continue 的循环。
示例:
package mainimport "fmt"func main() {// 不使用 label 标记fmt.Println("---- continue ---- ")for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)continue}}// 使用标记fmt.Println("---- continue label ----")re:for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)continue re}}
}
结果:
---- continue ----
i: 1
i2: 11
i2: 12
i2: 13
i: 2
i2: 11
i2: 12
i2: 13
i: 3
i2: 11
i2: 12
i2: 13
---- continue label ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
goto 语句
与 C 语言类似的,goto 语句可以无条件地转移到过程中指定的行。goto 语句通常与条件语句配合使用。可用来实现条件转移,构成循环,跳出循环体等功能。
通常的,在结构化程序设计中一般不主张使用 goto 语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。
格式:
goto label;
...label:statements;
示例:在变量 a 等于 15 的时候跳过本次循环并回到循环的开始语句 LOOP 处
package mainimport "fmt"func main() {/* 定义局部变量 */var a int = 10/* 循环 */LOOP: for a < 20 {if a == 15 {/* 跳过迭代 */a = a + 1goto LOOP}fmt.Printf("a 的值为 : %d\n", a)a++ }
}
Go 语言编程 — 逻辑控制语句相关推荐
- C 语言编程 — 逻辑控制语句
目录 文章目录 目录 前文列表 结构化程序设计 条件分支语句 if/else 语句 if 语句 if/else 语句 if/else-if/else 语句 嵌套 if 语句 switch 语句 swi ...
- C 语言编程 — 高级数据类型 — void 类型
目录 文章目录 目录 前文列表 void 类型 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> & ...
- C 语言编程 — 高级数据类型 — 字符串
目录 文章目录 目录 前文列表 字符串 字符串拷贝 字符串比较 strcmp strncmp 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> &l ...
- C 语言编程 — 指令行参数
目录 文章目录 目录 前文列表 命令行参数 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> < ...
- C 语言编程 — 编程实践
目录 文章目录 目录 前文列表 程序示例 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> < ...
- C 语言编程 — 编程规范
目录 文章目录 目录 前文列表 排版 注释 头文件 函数 标识符命名与定义 变量 宏.常量 代码逻辑 内存操作 日志打印 质量保证 单元测试 断言 安全性 可移植性 参考文档 前文列表 <程序编 ...
- C 语言编程 — GDB 调试工具
目录 文章目录 目录 前文列表 代码调试 GDB 启动 GDB 交互命令 运行程序 暂停程序 设置断点 设置观察点 设置捕捉点 打印信息 查询运行信息 分割窗口 前文列表 <程序编译流程与 GC ...
- C 语言编程 — 堆栈与内存管理
目录 文章目录 目录 前文列表 栈(Stack)和堆(Heap) 栈 堆 内存管理 动态分配内存 重新调整内存的大小和释放内存 malloc 函数详解 memset 初始化内存数据 前文列表 < ...
- C 语言编程 — 输入/输出与文件操作
目录 文章目录 目录 前文列表 输入/输出 scanf() 和 printf() getchar() 和 putchar() 文件操作 打开文件 关闭文件 写入文件 读取文件 二进制 I/O 函数 前 ...
最新文章
- 发光二极管pcb封装图画法_五个方面剖析SIP封装工艺,看懂SIP封装真正用途
- dataframe groupby_PySpark SQL——SQL和pd.DataFrame的结合体
- Android Studio或者Eclipse中的最常用的快捷键,最简单的,部分不适用eclipse
- 20162303 2016-2017-2 《程序设计与数据结构》第五周学习总结
- JavaScript基础04【逻辑、复制、关系、相等运算符、Unicode编码表】
- matlab读入txt数据_教程合集 | MATLAB文件读写(以nc与txt为例)
- 开课吧:一文解析Nexus是什么
- ubuntu修改启动项等待时间、修改启动项顺序、更改启动内核
- Tableau上面地图与条形图结合_Tableau 全新地图实战演示,更快、更高、更强
- ttc、otf、ttf文件制作以及相关数据增强(OCR)
- 单相和三相电源的区别
- 得到条形码的校验位函数
- RT-Thread Studio升级首推完美暗黑主题
- Macbook:关于MacBook屏幕发绿发红特殊问题的解决方法
- LeetCode 430. Flatten a Multilevel Doubly Linked List【链表/DFS/递归/迭代】中等
- android学习笔记----手机号码查询归属地
- C++ 1 之 冲刺期末不挂科的入门
- 程序员的种种崩溃瞬间
- 一英寸芯片大小_(整理)CCD芯片尺寸和镜头焦距计算方法.
- FPGA实现ADC采样芯片ADS8688的采样
热门文章
- mysql 添加多条数据类型_向数据库添加多条数据类型
- quicklook不能预览office_万物皆可格!给空格键施加神奇魔法的神器软件—快速预览工具QuicklookPC软件...
- eeglab教程系列(10)-绘制ERP图像
- 清华大学微纳脑机接口与机器人实验室:微纳系统机械设计研发工程师招聘
- 为衣服添加NFC功能:挥下袖子就能安全支付,打开车门坐进去就能启动汽车|Nature子刊...
- 「Smile」一下,轻松用Java玩转机器学习
- 高糊视频秒变4K!Facebook发布低分辨率视频实时渲染算法,网友:是好东西,但是玩不起...
- 英特尔AI医疗实战手册曝光:医生诊断提速10倍,推理时间减少85%
- GitHub一日千星:开头一张图,自动变成《我的世界》、乐高、十字绣风格,有Python就能跑...
- LINQ技术、EF技术都出来蛮久了,软件开发者、软件公司是否还有必要有自己的代码生成器?...