go语言学习笔记 — 基础 — 控制流:for循环语句
Posted Locutus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言学习笔记 — 基础 — 控制流:for循环语句相关的知识,希望对你有一定的参考价值。
在不少实际问题中,有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。以下为大多数编程语言循环程序的流程图:
Go语言的循环只有for一种表示方法,提供了以下两种循环处理语句:
循环类型 | 描述 |
---|---|
for循环 | 重复执行语句块 |
for嵌套循环 | 在for循环中嵌套一个或多个 for 循环 |
for循环可以通过break、goto、return、panic等语句强制退出循环。
1. for循环
for循环是一个循环控制结构,可以用来执行指定次数的循环。
1.1 for循环的语法
- go中for循环的一般形式(重要)
与C语言一样,go语言的循环只有一种形式,在for语句之间使用分号分隔。
for 初始语句; 条件表达式; 结束语句 {
循环体
}
循环体不停地进行循环,直到条件表达式返回false时,自动退出循环,接着执行for的“}”之后的语句。
- for中的初始语句 —— 开始循环时执行的语句
初始语句一般为赋值表达式,在第一次循环前执行,一般用于初始化控制变量。控制变量的作用域被限定在这个for循环之内。初始语句可以忽略不写,但初始语句之后的分号;必须写。
step := 2
for ;step > 0; step-- {
fmt.Println(step)
}
控制变量step放在for循环之前进行初始化,并且省略了初始化语句,此时控制变量step的作用域比在初始化语句中声明step的要大。
- for中的条件表达式 —— 控制是否循环的开关
条件表达式为关系表达式或逻辑表达式,是循环控制的判断条件。每次for循环开始前,计算条件表达式。如果值为true,则循环继续,否则循环结束。
a. 与C语言的for(;;)一样,下面代码忽略初始语句、条件表达式,但是保留结束语句。此时for循环持续执行(死循环),每次循环结束都会调用结束语句i++,循环的退出需要在循环体内调用break语句。
for ; ; i++ {
循环体
}
示例:当i大于10时,通过break语句跳出for循环,执行循环之外的语句。
var i int
for ; ; i++ { // 没有设置i的初始值
if i > 10 {
break
}
// code block
}
// code block
b. 无限循环(死循环)
条件表达式可以被忽略,忽略条件表达式的for循环默认形成无限循环。无限循环在收发处理中较常见,但需要有可控的方式结束循环,如break语句。
for {
循环体
}
把i++从for结束语句位置放到函数体末尾是等效的,这样的代码更有可读性。
var i int // 全局变量声明,下方赋值
for {
if i > 10 {
break
}
// code block
i++
}
c. 只有一个条件的for循环(将if判断整合到for中)
for condition {
循环体
}
下面代码与C语言的while类似,在for后添加一个条件表达式,满足条件时持续循环,否则结束循环。
在代码第3行中,将之前使用if i > 10 {}
的判断表达式进行取反,变为判断i小于等于10时持续进行循环。
var i int // 全局变量声明,初始化为零值
for i <= 10 {
fmt.Println(i)
i++
}
- for中的结束语句 —— 每次循环结束前执行的语句
结束语句一般为赋值表达式,给控制变量增量或减量。在结束每次循环前,都要调用结束语句;如果for循环被break、goto、return、panic等语句强制退出,就不会执行结束语句,如i++。
1.2 for循环的执行过程
以C语言风格的for循环为例
- 先对初始表达式赋初值
- 接着判断初始表达式是否满足条件表达式,若判别值为真(满足循环条件),则
先执行循环体内语句
,再执行结束语句
;然后进入下一次循环,判别条件。若判别值为真,仍是先执行循环体内语句
,再执行结束语句
;若判别值为假,不满足循环条件,就终止for循环,不再执行结束语句,改为执行循环体外的语句。
package main
import "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)
}
// 第二种形式
// a还是默认的int,初始是零值
for a < b {
a++
fmt.Printf("a 的值为: %d\\n", a)
}
// 没有元素的序号位要补0
for i,x := range numbers {
fmt.Printf("第 %d 位 x 的值å = %d\\n", i,x)
}
}
2. for嵌套循环
go语言允许用户在循环体内使用循环。go语言嵌套循环的格式:
for [condition | (init; condition; increment) | range] {
for [condition | (init; condition; increment) | range] {
statement(s);
}
statement(s);
}
输出2到100间的素数
package main
import "fmt"
func main() {
// 定义局部变量
var i, j int
for i = 2; i < 100; i++ {
for j = 2; j <= ( i/j ); j++ {
if i%j == 0 {
break // 如果发现因子,则不是素数
}
}
if j > (i/j) {
fmt.Printf("%d 是素数\\n", i)
}
}
}
输出9*9乘法表
package main
import "fmt"
func main() {
for i := 1; i <= 9; i++ { // 遍历行,决定处理第几行。i控制行,以及计算的最大值
for j := 1; j <= i; j++ { // 遍历列,决定处理对应行的哪些列。j控制每行的计算列数
fmt.Printf("%d*%d=%d ", j, i, j*i) // 每个计算式后边空出一格,便于罗列计算式
}
fmt.Println("") // 每执行完一行的所有列计算,就换行
}
}
/*
i = 1,i < 9,所以执行嵌套的循环
j = 1,i = 1,j <= i,所以执行fmt.Printf("%d*%d=%d ", j, i, j*i),1*1=1
j++,j=2 , i = 1,j <= i不成立,结束嵌套内的循环,所以执行fmt.Println(""),换行
i++,i = 2,i < 9,所以执行嵌套的循环
j = 1,i = 2,j <= i,所以执行fmt.Printf("%d*%d=%d ", j, i, j*i),1*2=2
j++,j = 2,i = 2,j <= i,fmt.Printf("%d*%d=%d ", j, i, j*i),2*2=2
j++,j = 3 , i = 2,j <= i不成立,结束嵌套内的循环,所以执行fmt.Println(""),换行
...
*/
3. 键值循环(for range)一一 直接获得对象的索引和数据
使用for range
遍历对象,直接获得对象的索引和数据。使用 for range
遍历数组、切片、字符串、map及通道(channel)。通过for range
遍历的返回值有一定的规律。
- for range遍历数组、切片、字符串,返回索引和值
遍历数组、切片
for key, value := range []int{1, 2, 3, 4} {
fmt.Printf("key:%d value:%d\\n", key, value)
}
遍历字符串时,key和value分别代表字符串的索引和字符串中的每一个字符
var str = "hello 你好"
for key, value := range str {
fmt.Printf("key:%d value:0x%x\\n", key, value)
}
value变量的实际类型是rune,即int32,以十六进制打印出来就是字符的编码。
- for range遍历字典map,返回键和值
func TestMapAddVisit(t *testing.T) {
scene := make(map[string]int)
t.Log(scene)
scene["route"] = 66
scene["brazil"] = 4
scene["china"] = 960
t.Log(scene)
// 使用for range,迭代map,遍历键值对
for k, v := range scene {
t.Log(k, v)
}
for _, v := range scene {
t.Log(v)
}
for k := range scene {
t.Log(k)
}
}
直接使用for range遍历map时,我们可以同时获得键key和值value。注意,遍历map时,输出的键值对是无序的,如果需要有序的键值对输出,需要对结果进行排序。
for k, v := range scene {
t.Log(k, v)
}
- for range遍历通道(channel),只返回通道内类型对应的数据
package main
import "fmt"
c := make(chan int) // 创建通道c
// 并发执行
go func () {
c <- 1 // 向通道c中添加数据
c <- 2 // 向通道c中添加数据
c <- 3 // 向通道c中添加数据
close(c) // 关闭通道
}() // 在声明goroutine结束后,马上并发执行
// 使用for range对通道c进行遍历,即不断地从通道中取数据, 直到通道被关闭
func main () {
for v := range c {
fmt.Println(v)
}
}
- 在遍历对象时,选择希望获得的变量(使代码更简单)
匿名变量_
可以理解为一种占位符。匿名变量变量不会进行内存空间分配,也不会占用一个变量的名字。在for range中,可以对 key使用匿名变量,也可以对value使用匿名变量。
只遍历值,把不需要的键改为匿名变量_的形式,可以使用如下形式:
for _, v := range scene {
t.Log(v)
}
只遍历键,无须把值改为匿名变量_的形式,忽略v即可。
for k := range scene {
t.Log(k)
}
4. 总结
- Go语言的for循环包含初始化语句、条件表达式、结束语旬, 这3个部分均可缺省
- for range支持对数组、切片、字符串、map、通道进行遍历操作
- 在需要时,可以使用匿名变量_,对
for range
变量的键值进行选取
以上是关于go语言学习笔记 — 基础 — 控制流:for循环语句的主要内容,如果未能解决你的问题,请参考以下文章
go语言学习笔记 — 基础 — 控制流:if条件(分支)语句