介紹
在電腦程式設計中,循環是一種程式結構,會不斷重複執行一段程式碼,通常會持續到滿足某個條件為止。在電腦程式設計中使用循環能讓您自動化和重複執行相似的任務多次。假設您有一串需要处理的文件,或者是想要計算文章的行數,您可以在程式碼中使用循環來解決這些問題。
在Go語言中,for
循環是根据 Loop 計數器或 Loop 變量来实现代码的重复执行。与其他编程语言相比,Go 只有 for
循环这种循环结构,如 while
、do
等。这使得您的代码更清晰、更易读,因为您无需担心多种策略来实现相同的循环结构。这种提高的可读性和降低的认知负荷也有助于开发过程中减少代码出错的可能性,与其他語言相比更是如此。
在本教程中,您將學習到Go語言中 for
循環的運作方式,包括其使用的三大變化。我們將從展示如何創建不同類型的 for
循環開始,接着是 如何遍历 Go 中的序列數據類型。最後,我們將解釋如何使用嵌套循環。
宣告ForClause和條件迴圈
為了應對各種使用案例,Go語言中有三种不同的方式創建for
迴圈,各有其特色。這是指使用條件、ForClause或範圍語句來創建for
迴圈。在本節中,我們將解釋如何宣告和使用ForClause和條件變體。
首先讓我們看看如何使用for
迴圈與ForClause。
一個ForClause迴圈被定義為具有初始語句,後跟條件,然後是後語句。它們按以下語法排列:
for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
[Action]
}
為了解釋前面元件的功能,讓我們看看使用ForClause語法 increments through a specified range of values 的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)
}
在宣告语句中,我們使用 `i++` 增量運算符每次迭代時將 loop 變數 i
增加一。
當我們運行這個程序時,輸出看起來是这样的:
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
我們也可以使用我們的宣告語句以不同的值增加。這在其他語言中的步進(step)相似:
首先,讓我們用一個正值使用宣告語句:
for i := 0; i < 15; i += 3 {
fmt.Println(i)
}
在這個情況下,`for` 迴圈被設定為從 0 到 15 打印出數字,但增加量為 3,所以只打印出每隔一個數字,像這樣:
Output0
3
6
9
12
我們也可以用一個負數來对我们的 post statement argument,但我們必須調整我們的initial statement和condition arguments適當:
這裡,我們將 i
設定為一個初始值 of 100
,使用條件 of i < 0
来停止 at 0
,然後post statement decrement the value by 10 with the -=
operator。loop begins at 100
and ends at 0
,decreasing by 10 with each iteration。We can see this happen in the output:
Output100
90
80
70
60
50
40
30
20
10
You can also exclude the initial statement and the post statement from the for
syntax,and only use the condition。This is what is known as a Condition loop:
i := 0
for i < 5 {
fmt.Println(i)
i++
}
This time,we declared the variable i
separately from the for
loop in the preceding line of code。The loop only has a condition clause that checks to see if i
is less than 5
。As long as the condition evaluates to true
,the loop will continue to iterate。
Sometimes you may not know the number of iterations you will need to complete a certain task。In that case,you can omit all statements,and use the break
keyword to exit execution:
for {
if someCondition {
break
}
// do action here
}
An example of this may be if we are reading from an indeterminately sized structure like a buffer and we don’t know when we will be done reading:
在前面的代码中,buf := bytes.NewBufferString("one
声明了一个包含一些数据的缓冲区。因为不知道何时缓冲区会读完,我们使用一个没有条件的
two
three
four
")for
循环。在 for
循环内部,我们使用 line, err = buf.ReadString
来从缓冲区读取一行数据并检查读取是否出现错误。如果有错误,我们处理错误,并且使用
")break
关键字退出循环。通过这些 break
点,你不需要在循环中包含一个条件来停止循环。在这里,我们学习了如何声明一个 ForClause 循环以及如何使用它来迭代已知范围的值。我们还学习了如何使用 Condition 循环直到满足特定条件才停止。接下来,我们将学习如何在 RangeClause 中使用迭代序列数据类型。
在这一节中,我们了解了如何声明一个ForClause循环,以及如何使用它来遍历已知的范围值。我们也学会了如何使用Condition循环,直到满足特定的条件才退出循环。在这里,我们了解到如何声明一个RangeClause循环,以及如何使用它来迭代顺序数据类型。下一节,我们将学习如何在RangeClause中使用迭代顺序数据类型。
使用Range子句迭代顺序数据类型
在 Go 語言中,常用 for
迴圈來遍歷序列或集合類型的數據類型,如 切片(slices)、數組(arrays) 和 字符串(strings)。為了更容易地做到这一点,我們可以使用带有 RangeClause 語法的 for
迴圈。雖然您可以用 ForClause 語法遍歷序列數據類型,但 RangeClause 更 cleaner 且易於閱讀。
在查看如何使用 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
。
有时我們只想取切片元素内的值,不想取索引。如果將前面的程式碼更改为只Print出值的話,就會出現編譯時錯誤:
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
是在loop中 Declaration的,但从未使用,編譯器將會回應為i Declaration and not used
。這是同樣的錯誤,你在Go中每次 Declaration一個Variable而沒有使用它時都會收到。
因為這個原因,Go有空白Identifier,也就是一个下划线(_
)。在loop中,你可以用空白Identifier忽略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
operator來填滿slice的值:
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
將返回 key 和 value:
Outputcolor: blue
location: ocean
name: Sammy
animal: shark
注意: 必須注意的是,map 返回的順序是随機的。每次運行此程序時,您可能會得到不同的結果。
現在我們已經學習了如何使用 range
for
循環遍歷序列數據,讓我們來看一下如何在循環中使用循環。
嵌套循環
在 Go 語言中,如同其他程式設計語言一樣,可以嵌套循環。嵌套(Nesting)是指我們在其中一個結構內放入另一個結構。在這個情況下,嵌套循環就是在另一個循環內发生的循環。當你想對數據集中的每個元素執行一個循環动作時,嵌套循環會很有用。
嵌套循環在結構上與嵌套的 `if` 語句相似。它們是这样構建的:
for {
[Action]
for {
[Action]
}
}
程序首先遇到外層循環,執行其第一次迭代。這一次迭代觸發了內置的嵌套循環,然後該嵌套循環運行到完成。然後程序返回外層循環的頂部,完成第二個迭代並再次觸發嵌套循環。同樣,嵌套循環運行到完成,然後程序返回外層循環的頂部,直到序列为完成,或者有 `break` 或其他語句干擾这个过程。
讓我們来实现一个嵌套的 `for` 循环,以便我們可以更仔细地观察。在此示例中,外層循環將遍历一個整數切片 `numList`,而內層循環將遍历一個字符串切片 `alphaList`。
當我們運行此程序時,我們將獲得以下輸出:
Output1
a
b
c
2
a
b
c
3
a
b
c
上述内容已經翻譯為traditional chinese如下:
程序完成外層loop的第一次迭代時,會打印出1
,然後引發内層loop的完成,連續打印出a
、b
、c
。一旦內層loop完成,程式回到外層loop的顶部,打印出2
,然後再次打印整個內層loop(a
、b
、c
),以此類推。
嵌套for
loop可以用来遍歷由切片组成的切片。如果我們只使用一個for
loop,程式將會將每個內部list作為一個項目輸出:
Output[0 1 2]
[-1 -2 -3]
[9 8 7]
為了訪問内部slices中的每個item,我们将實現一个嵌套for
loop:
Output0
1
2
-1
-2
-3
9
8
7
當我們使用嵌套for
loop時,我們能夠遍歷内部的item。
結論
在這篇教程中,我們学习了如何在Go中 Declaration and use of for
loops to solve repetitive tasks. We also learned the three different variations of a for
loop and when to use them. To learn more about for
loops and how to control the flow of them, read Using Break and Continue Statements When Working with Loops in Go.
Source:
https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go