简介
在计算机编程中,循环是一种代码结构,它会重复执行一段代码,通常直到满足某个条件为止。在计算机编程中使用循环可以让你自动化并多次重复相似的任务。想象一下,如果你需要处理一个文件列表,或者你想计算一篇文章中的行数,你会在代码中使用循环来解决这些问题。
在Go语言中,for
循环实现了基于循环计数器或循环变量的代码重复执行。与其他具有多种循环构造,如while
、do
等编程语言不同,Go只有一种for
循环。这使得你的代码更加清晰易读,因为你无需担心使用多种策略来实现相同的循环结构。这种提高的可读性和降低的认知负担也会使你的代码比其他语言更容易避免错误。
在本教程中,你将学习Go语言中for
循环的工作原理,包括其使用的三大变体。我们将首先展示如何创建不同类型的for
循环,然后是如何遍历Go中的顺序数据类型。最后,我们将解释如何使用嵌套循环。
声明ForClause和条件循环
为了应对各种用例,Go语言中有三种创建for
循环的方式,每种方式都有其自身的特点。这些是创建具有条件、ForClause或RangeClause的for
循环。在本节中,我们将解释如何声明和使用ForClause和条件变体。
首先让我们看看如何使用带有ForClause的for
循环。
带有ForClause的ForClause循环定义为具有初始声明,后跟条件,然后是后声明。它们按照以下语法排列:
for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
[Action]
}
为了解释前面组件的作用,让我们看看使用ForClause语法的for
循环如何通过指定范围递增值:
让我们分解这个循环并识别每个部分。
循环的第一部分是i := 0
。这是初始声明:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
它声明了一个名为i
的变量,并将初始值设置为0
。
接下来是条件:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
在这个条件中,我们表示,只要i
小于5
的值,循环应该继续循环。
最后,我们有后声明:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
在for循环的声明中,我们使用i++
增量操作符每次迭代时将循环变量i
增加1。
当我们运行这个程序时,输出结果如下:
Output0
1
2
3
4
循环运行了5次。最初,它将i
设置为0
,然后检查i
是否小于5
。由于i
的值小于5
,循环执行了,并执行了fmt.Println(i)
动作。循环结束后,调用了i++
的后置声明,i
的值增加了1。
注意:请记住,在编程中我们通常从索引0开始,这就是为什么虽然输出了5个数字,但它们的范围是0-4。
我们不仅限于从0开始或以指定的值结束。我们可以为我们的初始声明分配任何值,在后置声明中也可以停止任何值。这允许我们创建任何所需的范围来循环遍历:
在这里,迭代从20(包含)到25(不包含),所以输出结果如下:
Output20
21
22
23
24
我们还可以使用后置声明以不同的值增加。这与其他语言中的步长
类似:
首先,我们使用带有正值的后置声明:
for i := 0; i < 15; i += 3 {
fmt.Println(i)
}
在这个例子中,for循环设置为从0到15打印数字,但以3为增量,所以只打印每第三个数字,如下所示:
Output0
3
6
9
12
我们也可以使用负值作为我们的post语句参数来倒序迭代,但是我们必须相应地调整我们的初始声明和条件参数:
在这里,我们将i
设置为初始值为100
,使用条件i < 0
来在i
达到0
时停止,并在post语句中使用-=
操作符将i
减少10。循环从100
开始,结束于0
,每次迭代减少10。我们可以通过输出看到这一点:
Output100
90
80
70
60
50
40
30
20
10
您也可以省略初始声明和后置语句,只使用条件。这被称为条件循环:
i := 0
for i < 5 {
fmt.Println(i)
i++
}
这一次,我们在循环之前单独声明了变量i
。循环只有检查i
是否小于5
的条件。只要条件评估为true
,循环就会继续执行。
有时候你可能不知道你需要完成多少次迭代才能完成某个任务。在这种情况下,你可以省略所有的语句,并使用break
关键字退出执行:
for {
if someCondition {
break
}
// do action here
}
一个例子可能是如果我们正在从大小不确定的结构(如缓冲区)中读取,并且我们不知道何时会读完:
在前面的代码中,buf :=bytes.NewBufferString("one\ntwo\nthree\nfour\n")
声明了一个包含一些数据的缓冲区。因为我们不知道何时会读完缓冲区,所以我们创建了一个没有子句的 for
循环。在 for
循环内部,我们使用 line, err := buf.ReadString('\n')
从缓冲区中读取一行,并检查是否有从缓冲区读取时的错误。如果有的话,我们处理错误,并使用 break
关键字退出 for 循环。有了这些 break
点,你不需要包含一个停止循环的条件。
在本节中,我们学习了如何声明 ForClause 循环并使用它来遍历一个已知的值范围。我们还学习了如何使用 Condition 循环在满足特定条件时进行迭代。接下来,我们将学习如何使用 RangeClause 遍历顺序数据类型。
使用 RangeClause 遍历顺序数据类型
在Go语言中,通常使用for
循环来遍历序列或集合数据类型,如切片(slices)、数组和字符串(strings)。为了更容易地进行这种操作,我们可以使用带有RangeClause语法的for
循环。尽管你可以使用ForClause语法遍历顺序数据类型,但RangeClause更简洁,也更容易阅读。
在我们查看如何使用RangeClause之前,让我们先看看如何使用ForClause语法遍历切片:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i := 0; i < len(sharks); i++ {
fmt.Println(sharks[i])
}
}
运行这段代码将会输出以下内容,打印出切片的每个元素:
Outputhammerhead
great white
dogfish
frilled
bullhead
requiem
现在,让我们使用RangeClause来执行相同的操作:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i, shark := range sharks {
fmt.Println(i, shark)
}
}
在这个例子中,我们打印出列表中的每个项目。虽然我们使用了i
和shark
这两个变量,但我们本可以将变量命名为其他任何有效的变量名,并且我们仍然会得到相同的输出:
Output0 hammerhead
1 great white
2 dogfish
3 frilled
4 bullhead
5 requiem
当对切片使用range
时,它总是返回两个值。第一个值是当前循环迭代的索引,第二个值是该索引处的值。在这个例子中,第一次迭代的索引是0
,值是hammerhead
。
有时,我们只想打印切片中的元素值,而不想要索引。如果我们将前面的代码更改为只打印值,则会收到编译时错误:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i, shark := range sharks {
fmt.Println(shark)
}
}
Outputsrc/range-error.go:8:6: i declared and not used
因为i是在循环中声明的,但从未使用过,因此编译器会响应i declared and not used(i已声明但未使用)。这是Go中任何时间你声明一个变量而没有使用它时都会出现的错误。
由于这个原因,Go有一个空白标识符(空格),在for
循环中,你可以使用空白标识符忽略range
关键字返回的任何值。在这种情况下,我们想要忽略索引,这是range
关键字返回的两个参数中的第一个。
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for _, shark := range sharks {
fmt.Println(shark)
}
}
Outputhammerhead
great white
dogfish
frilled
bullhead
requiem
这显示了循环迭代了字符串切片,并打印了切片中的每个项目而没有索引。
你也可以使用range
来向列表添加项:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for range sharks {
sharks = append(sharks, "shark")
}
fmt.Printf("%q\n", sharks)
}
Output['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem', 'shark', 'shark', 'shark', 'shark', 'shark', 'shark']
这里,我们在sharks
切片的长度上为每个项目添加了一个占位符字符串"shark"
。
注意,如果我们不需要使用range
操作符返回的任何值,我们可以完全省略range
语句的声明部分。Go允许我们省略range
语句的整个声明部分,如果不需要使用两个返回值的话。
我们还可以使用range
运算符来填充切片:
package main
import "fmt"
func main() {
integers := make([]int, 10)
fmt.Println(integers)
for i := range integers {
integers[i] = i
}
fmt.Println(integers)
}
在这个示例中,切片 integers
初始化为十个空值,但是 for
循环设置了列表中的所有值:
Output[0 0 0 0 0 0 0 0 0 0]
[0 1 2 3 4 5 6 7 8 9]
第一次打印切片 integers
的值时,我们看到全部是零。然后我们遍历每个索引,并将值设置为当前索引。然后当我们第二次打印 integers
的值时,显示它们现在都有从 0
到 9
的值。
我们还可以使用 range
操作符来遍历字符串中的每个字符:
OutputS
a
m
m
y
当遍历一个 map 时,range
将返回 键 和 值:
Outputcolor: blue
location: ocean
name: Sammy
animal: shark
注意:请注意,地图返回的顺序是随机的。每次运行此程序时,您可能得到不同的结果。
现在我们已经学会了如何使用 range
for
循环遍历顺序数据,让我们来看看如何在循环中使用循环。
嵌套循环
在Go语言中,循环可以像在其他编程语言中一样嵌套。嵌套是指我们将一个结构放在另一个结构内部。在这种情况下,嵌套循环是发生在另一个循环内部的循环。当您希望对数据集中的每个元素执行循环操作时,嵌套循环非常有用。
嵌套循环在结构上与嵌套if
语句相似。它们的结构如下:
for {
[Action]
for {
[Action]
}
}
程序首先遇到外层循环,执行其第一次迭代。这次迭代触发了内嵌的、嵌套循环,然后它运行到完成。然后程序返回到外层循环的顶部,完成第二次迭代并再次触发嵌套循环。同样,嵌套循环运行到完成,程序再返回到外层循环的顶部,直到序列完成或break或其他语句打断过程。
让我们实现一个嵌套的for
循环,以便我们可以更仔细地观察。在这个例子中,外层循环将遍历一个名为numList
的整数切片,内层循环将遍历一个名为alphaList
的字符串切片。
当我们运行这个程序时,我们将得到以下输出:
Output1
a
b
c
2
a
b
c
3
a
b
c
输出显示程序通过打印1
完成了外层循环的第一次迭代,这随后触发了内层循环的完成,连续打印a
、b
、c
。一旦内层循环完成,程序返回到外层循环的顶部,打印2
,然后再次打印整个内层循环(a
、b
、c
),等等。
嵌套的for
循环在遍历由切片组成的切片中非常有用。在一个由切片组成的切片中,如果我们只使用一个for
循环,程序将输出每个内部列表作为一个项目:
Output[0 1 2]
[-1 -2 -3]
[9 8 7]
为了访问内部切片的每个单独的项目,我们将实现一个嵌套的for
循环:
Output0
1
2
-1
-2
-3
9
8
7
当我们在这里使用嵌套的for
循环时,我们能够遍历包含在切片中的各个项目。
结论
在本教程中,我们学习了如何声明和使用for
循环来解决Go中的重复任务。我们还学习了for
循环的三种不同变体以及何时使用它们。为了了解更多关于for
循环以及如何控制它们的流程,请阅读在Go中使用break和continue语句时循环的工作。
Source:
https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go