循环语句
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。
以下为大多编程语言循环程序的流程图:
for循环
基本语法
GO为了精简关键字,没有提供while
循环,所有的循环都通过for
循环实现。
基本语法
for init; condition; post { }
for 初始化;迭代条件;步进操作{
循环体
}
参数解释
【init】
一般为赋值表达式,给控制变量赋初值;
【condition】
关系表达式或逻辑表达式,循环控制条件;
【post】
一般为赋值表达式,给控制变量增量或减量。
执行流程
1、先对表达式 1 赋初值;
2、判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。
举例
package iterative
import "fmt"
func IterativeFor(){
//for循环
for i:=0;i<=10;i++{
if(i%2==0){
fmt.Printf("数字%d是偶数\n",i)
}
}
}
输出结果
数字0是偶数
数字2是偶数
数字4是偶数
数字6是偶数
数字8是偶数
数字10是偶数
省略条件
for循环的三个条件可以组合使用,例如省略一项或多项达到别的效果。
初始赋值项
package iterative
import "fmt"
func IterativeFor(){
//for循环
for i:=0;i<=10;i++{
if(i%2==0){
fmt.Printf("数字%d是偶数\n",i)
}
}
//报错
fmt.Println(i)
}
直接在for循环中初始化的变量的作用域局限于该for循环,不能在外部访问。
语法
//省略掉了赋值项
//初始值将从外部寻找
for ;condition;post{
}
举例
package iterative
import "fmt"
func IterativeFor(){
//省略初始赋值
age :=15
for ;age<=18;age++{
if(age<18){
fmt.Printf("您才%d岁,尚未成年,请快快长大\n",age)
}else{
fmt.Printf("恭喜您,您已经%d了,可以去上班了\n",age)
}
}
}
结果
您才15岁,尚未成年,请快快长大
您才16岁,尚未成年,请快快长大
您才17岁,尚未成年,请快快长大
恭喜您,您已经18了,可以去上班了
优势:变量可以在for循环外访问
迭代条件
如果省略了迭代条件将陷入死循环,此时需要使用break
显式跳出。
语法
//省略掉了迭代条件
//for循环将不知何时退出循环,所以会陷入死循环
for init;;post{
}
举例
package iterative
import "fmt"
func IterativeFor(){
//省略迭代条件
for i:=0;;i++{
if(i%2==0){
fmt.Printf("数字%d是偶数\n",i)
}
}
}
跳出死循环
package iterative
import "fmt"
func IterativeFor(){
//省略迭代条件
for i:=0;;i++{
if(i%2==0){
fmt.Printf("数字%d是偶数\n",i)
}
if(i>20){
//跳出死循环,相当于在内部添加迭代终止条件
break
}
}
}
增量条件
省略增量条件也将陷入死循环,因为迭代对象不发生改变,永远无法满足迭代终止条件。
语法
//省略掉了增量条件
//for循环无法达到迭代终止条件,陷入死循环
for init;condition;{
}
要终止死循环,只能在循环内部添加增量条件。
举例
package iterative
import "fmt"
func IterativeFor(){
//省略增量条件
for i:=0;i<20; {
if(i%2==0){
fmt.Printf("数字%d是偶数\n",i)
}
}
}
跳出死循环
package iterative
import "fmt"
func IterativeFor(){
//省略迭代条件
for i:=0;i<=10;{
if(i%2==0){
fmt.Printf("数字%d是偶数\n",i)
}
//添加增量条件
i++
}
}
分号的省略
1.初始值是一个赋值语句
2.迭代终止条件是一个布尔表达式
3.增量条件是一个步进表达式
由于三项非常容易区别,所以如果我们省略了哪一项,他后面对应的;
也可以省略。
等价
等价于while
和其他语言的while
一样:
for condition {
}
//带分号识别度更高
for ;condition; {
}
等价于死循环
for ;;;{
}
for true {
}
//把分号都省略了
for {
}
for…range
相当于js中的for...of
和python中的for...in
.
Go 语言中 range 关键字用于 for 循环中迭代整型(int)、数组(array)、切片(slice)、通道(channel)、字符串(string)或集合(map)的元素。
在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。
基本语法
for key, value := range oldMap {
newMap[key] = value
}
以上代码中的 key 和 value 是可以省略。
如果只想读取 key,格式如下:
for key := range oldMap
//或者
for key, _ := range oldMap
如果只想读取 value,格式如下:
for _, value := range oldMap
使用范围及含义
适用范围 | key | value | desc |
---|---|---|---|
int整数类型 | 从0到该整数 | 无 | 从Go1.22新增支持 |
string字符串类型 | 索引 | 值 | |
array数组类型 | 索引 | 值 | |
slice切片类型 | 索引 | 值 | |
map映射类型 | 键 | 值 | |
chan通道类型 | 从通道接收的值 | 无 |
实例举例
迭代整型
package iterative
import "fmt"
func IterativeRange(){
//适用整数
for v := range 5 {
fmt.Println(v)
}
}
结果
0
1
2
3
4
注意
这种方式目前局限性很大,默认只能实现[0,n)
,如果我们要实现[m,n)
,可以使用手动过滤,例如:
package iterative
import "fmt"
func IterativeRange(){
//我们要实现[5,10)
for v := range 10 {
//手动过滤不满足条件的
if(v<5){
continue
}
fmt.Println(v)
}
}
迭代数组和切片
因为数组和切片在用这种迭代时基本一致。
package iterative
import "fmt"
func IterativeRange(){
//适用于数组
var arr = [5]string{"a","b","c","d","e"}
for key,val := range arr{
fmt.Printf("数组arr的索引为%d,值为%s\n",key,val)
}
//适用于切片
var slice1 = []string{"a","b","c","d","e"}
for key,val := range slice1{
fmt.Printf("切片slice1的索引为%d,值为%s\n",key,val)
}
}
结果
数组arr的索引为0,值为a
数组arr的索引为1,值为b
数组arr的索引为2,值为c
数组arr的索引为3,值为d
数组arr的索引为4,值为e
切片slice1的索引为0,值为a
切片slice1的索引为1,值为b
切片slice1的索引为2,值为c
切片slice1的索引为3,值为d
切片slice1的索引为4,值为e
迭代字符串
range 迭代字符串时,返回每个字符的索引和 Unicode 代码点(rune)。
package iterative
import "fmt"
func IterativeRange(){
//迭代字符串
var str1 string= "hello 人类!"
for key,val :=range str1{
fmt.Printf("该字符位于字符串的下标%d,rune值为%v,字符值为%c\n",key,val,val)
}
}
结果
该字符位于字符串的下标0,rune值为104,字符值为h
该字符位于字符串的下标1,rune值为101,字符值为e
该字符位于字符串的下标2,rune值为108,字符值为l
该字符位于字符串的下标3,rune值为108,字符值为l
该字符位于字符串的下标4,rune值为111,字符值为o
该字符位于字符串的下标5,rune值为32,字符值为
该字符位于字符串的下标6,rune值为20154,字符值为人
该字符位于字符串的下标9,rune值为31867,字符值为类
该字符位于字符串的下标12,rune值为33,字符值为!
注意
直接得到的值是数字编码,操作时可能需要将数字编码转换成对应字符。
迭代映射map
package iterative
import "fmt"
func IterativeRange(){
//迭代map
map1 := map[string]string{
"a":"apple",
"b":"bear",
"c":"cat",
}
for key,val := range map1 {
fmt.Printf("map的键为%s,值为%s\n",key,val)
}
}
结果
map的键为a,值为apple
map的键为b,值为bear
map的键为c,值为cat
迭代遍历通道
range 遍历从通道接收的值,直到通道关闭。
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
for key := range ch {
fmt.Println(key)
}
结果
1
2