前書き
コンピュータプログラミングでは、loopはループしてコードの一部を繰り返し実行するコード構造であり、多くの場合、何らかの条件が満たされるまで実行されます。 コンピュータープログラミングでループを使用すると、同様のタスクを複数回自動化して繰り返すことができます。 処理する必要のあるファイルのリストがある場合、または記事の行数をカウントする場合を想像してください。 これらのタイプの問題を解決するには、コードでループを使用します。
Goでは、for
ループは、ループカウンターまたはループ変数に基づいてコードの繰り返し実行を実装します。 while
、do
などの複数のループ構造を持つ他のプログラミング言語とは異なり、Goにはfor
ループしかありません。 これは、同じループ構造を実現するために複数の戦略を心配する必要がないため、コードをより明確で読みやすくするのに役立ちます。 開発時の読みやすさの向上と認知負荷の軽減により、他の言語よりもコードがエラーになりにくくなります。
このチュートリアルでは、Goのfor
ループがどのように機能するかを、その使用法の3つの主要なバリエーションを含めて学習します。 まず、さまざまなタイプのfor
ループを作成する方法を示し、次にsequential data types in Goをループする方法を示します。 最後に、ネストされたループの使用方法を説明します。
ForClauseおよび条件ループの宣言
さまざまなユースケースを説明するために、Goでfor
ループを作成する3つの異なる方法があり、それぞれに独自の機能があります。 これらは、Condition、ForClause、またはRangeClauseでfor
ループを作成するためのものです。 このセクションでは、ForClauseおよびConditionバリアントを宣言して使用する方法を説明します。
まず、ForClauseでfor
ループを使用する方法を見てみましょう。
ForClause loopは、initial statement、condition、post statementの順で定義されます。 これらは、次の構文で配置されます。
for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
[Action]
}
上記のコンポーネントの機能を説明するために、ForClause構文を使用して指定された値の範囲をインクリメントするfor
ループを見てみましょう。
for i := 0; i < 5; i++ {
fmt.Println(i)
}
このループを分解して、各部分を識別しましょう。
ループの最初の部分はi := 0
です。 これは最初のステートメントです。
for i := 0; i < 5; i++ {
fmt.Println(i)
}
i
という変数を宣言し、初期値を0
に設定していることを示しています。
次は条件です。
for i := 0; i < 5; i++ {
fmt.Println(i)
}
この状態で、i
が5
の値よりも小さい間、ループはループを継続する必要があると述べました。
最後に、postステートメントがあります。
for i := 0; i < 5; i++ {
fmt.Println(i)
}
postステートメントでは、i++
increment演算子を使用して、反復が発生するたびにループ変数i
を1ずつインクリメントします。
このプログラムを実行すると、出力は次のようになります。
Output0
1
2
3
4
ループは5回実行されました。 最初に、i
を0
に設定し、次にi
が5
よりも小さいかどうかを確認しました。 i
の値が5
未満だったため、ループが実行され、fmt.Println(i)
のアクションが実行されました。 ループが終了した後、i++
のpostステートメントが呼び出され、i
の値が1ずつ増加しました。
[.note]#Note:プログラミングではインデックス0から開始する傾向があるため、5つの数値が出力されますが、0〜4の範囲であることに注意してください。
#
0から開始するか、指定した値で終了することに限定されません。 最初のステートメントに任意の値を割り当てることができ、また、ポストステートメントの任意の値で停止できます。 これにより、必要な範囲を作成してループすることができます。
for i := 20; i < 25; i++ {
fmt.Println(i)
}
ここで、反復は20(包括的)から25(包括的)に変わるため、出力は次のようになります。
Output20
21
22
23
24
postステートメントを使用して、異なる値で増分することもできます。 これは、他の言語のstep
に似ています。
最初に、正の値を持つpostステートメントを使用しましょう。
for i := 0; i < 15; i += 3 {
fmt.Println(i)
}
この場合、for
ループは、0から15までの数値が出力されるように設定されていますが、3ずつ増加するため、次のように3つおきの数値のみが出力されます。
Output0
3
6
9
12
postステートメント引数に負の値を使用して逆方向に反復することもできますが、それに応じて初期ステートメント引数と条件引数を調整する必要があります。
for i := 100; i > 0; i -= 10 {
fmt.Println(i)
}
ここでは、i
を100
の初期値に設定し、i < 0
の条件を使用して0
で停止し、postステートメントは%で値を10ずつ減らします。 (t4)s演算子。 ループは100
で始まり、0
で終わり、反復ごとに10ずつ減少します。 出力でこれが発生することがわかります。
Output100
90
80
70
60
50
40
30
20
10
for
構文から最初のステートメントとpostステートメントを除外し、条件のみを使用することもできます。 これはCondition loopとして知られているものです:
i := 0
for i < 5 {
fmt.Println(i)
i++
}
今回は、前のコード行でfor
ループとは別に変数i
を宣言しました。 ループには、i
が5
よりも小さいかどうかを確認する条件句のみがあります。 条件がtrue
と評価される限り、ループは繰り返され続けます。
特定のタスクを完了するために必要な反復回数がわからない場合があります。 その場合、すべてのステートメントを省略し、break
キーワードを使用して実行を終了できます。
for {
if someCondition {
break
}
// do action here
}
この例としては、bufferのようなサイズが不定の構造から読み取っていて、いつ読み取りが完了するかわからない場合があります。
buffer.go
package main
import (
"bytes"
"fmt"
"io"
)
func main() {
buf := bytes.NewBufferString("one\ntwo\nthree\nfour\n")
for {
line, err := buf.ReadString('\n')
if err != nil {
if err == io.EOF {
fmt.Print(line)
break
}
fmt.Println(err)
break
}
fmt.Print(line)
}
}
上記のコードでは、buf :=bytes.NewBufferString("one
two
three
four
")
はいくつかのデータを含むバッファーを宣言しています。 バッファがいつ読み取りを終了するかわからないため、句のないfor
ループを作成します。 for
ループ内で、line, err := buf.ReadString('
')
を使用してバッファーから行を読み取り、バッファーからの読み取り中にエラーが発生したかどうかを確認します。 あった場合は、エラーとuse the break
keyword to exit the for loopに対処します。 これらのbreak
ポイントを使用すると、ループを停止するための条件を含める必要はありません。
このセクションでは、ForClauseループを宣言し、それを使用して既知の値の範囲を反復処理する方法を学びました。 また、特定の条件が満たされるまで条件ループを使用して繰り返す方法も学びました。 次に、RangeClauseを使用してシーケンシャルデータ型を反復処理する方法を学習します。
RangeClauseを使用したシーケンシャルデータ型のループ
Goでは、slices, arraysやstringsなどのシーケンシャルまたはコレクションデータ型の要素を反復処理するためにfor
ループを使用するのが一般的です。 これを簡単にするために、RangeClause構文でfor
ループを使用できます。 ForClause構文を使用してシーケンシャルデータ型をループできますが、RangeClauseはより簡潔で読みやすいです。
RangeClauseを使用する前に、ForClause構文を使用してスライスを反復処理する方法を見てみましょう。
main.go
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を使用して同じアクションセットを実行しましょう。
main.go
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
を使用しましたが、変数を他のvalid variable nameと呼ぶこともでき、同じ出力が得られます。
Output0 hammerhead
1 great white
2 dogfish
3 frilled
4 bullhead
5 requiem
スライスでrange
を使用すると、常に2つの値が返されます。 最初の値はループの現在の反復が含まれるインデックスになり、2番目の値はそのインデックスの値になります。 この場合、最初の反復では、インデックスは0
であり、値はhammerhead
でした。
インデックスではなく、スライス要素内の値のみが必要な場合があります。 ただし、上記のコードを変更して値のみを出力すると、コンパイル時エラーが発生します。
main.go
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
はfor
ループで宣言されていますが、使用されていないため、コンパイラーはi declared and not used
のエラーで応答します。 これは、変数を宣言して使用しないときにGoで受け取るエラーと同じです。
このため、Goにはアンダースコア(_
)であるblank identifierがあります。 for
ループでは、空白の識別子を使用して、range
キーワードから返された値を無視できます。 この場合、返される最初の引数であるインデックスを無視します。
main.go
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
この出力は、for
ループが文字列のスライスを反復処理し、インデックスなしでスライスから各アイテムを出力したことを示しています。
range
を使用して、リストにアイテムを追加することもできます。
main.go
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
演算子からの戻り値を無視するために、空白の識別子_
を使用する必要がないことに注意してください。 Goを使用すると、どちらの戻り値も使用する必要がない場合に、range
ステートメントの宣言部分全体を省略できます。
range
演算子を使用して、スライスの値を入力することもできます。
main.go
package main
import "fmt"
func main() {
integers := make([]int, 10)
fmt.Println(integers)
for i := range integers {
integers[i] = i
}
fmt.Println(integers)
}
この例では、スライスintegers
は10個の空の値で初期化されますが、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
演算子を使用して、文字列内の各文字を反復処理することもできます。
main.go
package main
import "fmt"
func main() {
sammy := "Sammy"
for _, letter := range sammy {
fmt.Printf("%c\n", letter)
}
}
OutputS
a
m
m
y
mapを反復処理すると、range
はkeyとvalueの両方を返します。
main.go
package main
import "fmt"
func main() {
sammyShark := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
for key, value := range sammyShark {
fmt.Println(key + ": " + value)
}
}
Outputcolor: blue
location: ocean
name: Sammy
animal: shark
[.note]#Note:マップが返される順序はランダムであることに注意することが重要です。 このプログラムを実行するたびに、異なる結果が得られる場合があります。
#
range
for
ループを使用してシーケンシャルデータを反復処理する方法を学習したので、ループ内でループを使用する方法を見てみましょう。
ネストされたForループ
ループは、他のプログラミング言語と同様に、Goでネストできます。 Nestingは、ある構成が別の構成の中にある場合です。 この場合、ネストされたループは、別のループ内で発生するループです。 これらは、データセットのすべての要素でループアクションを実行する場合に役立ちます。
ネストされたループは、構造的にnested if
statementsに似ています。 それらは次のように構築されます:
for {
[Action]
for {
[Action]
}
}
プログラムは最初に外側のループに遭遇し、最初の反復を実行します。 この最初の反復により、内部のネストされたループがトリガーされ、完了まで実行されます。 その後、プログラムは外側のループの先頭に戻り、2回目の反復を完了して、再びネストされたループをトリガーします。 繰り返しますが、ネストされたループは完了するまで実行され、プログラムはシーケンスが完了するか、ブレークまたはその他のステートメントによってプロセスが中断されるまで、外側のループの先頭に戻ります。
ネストされたfor
ループを実装して、詳しく見てみましょう。 この例では、外側のループはnumList
と呼ばれる整数のスライスを反復処理し、内側のループはalphaList
と呼ばれる文字列のスライスを反復処理します。
main.go
package main
import "fmt"
func main() {
numList := []int{1, 2, 3}
alphaList := []string{"a", "b", "c"}
for _, i := range numList {
fmt.Println(i)
for _, letter := range alphaList {
fmt.Println(letter)
}
}
}
このプログラムを実行すると、次の出力が表示されます。
Output1
a
b
c
2
a
b
c
3
a
b
c
出力は、プログラムが1
を出力することによって外部ループの最初の反復を完了し、次に内部ループの完了をトリガーして、a
、b
、c
を連続して出力することを示しています。 。 内側のループが完了すると、プログラムは外側のループの先頭に戻り、2
を出力してから、内側のループ全体(a
、b
、c
を再度出力します。 )s)など。
ネストされたfor
ループは、スライスで構成されるスライス内のアイテムを反復処理するのに役立ちます。 スライスで構成されるスライスで、for
ループを1つだけ使用すると、プログラムは各内部リストをアイテムとして出力します。
main.go
package main
import "fmt"
func main() {
ints := [][]int{
[]int{0, 1, 2},
[]int{-1, -2, -3},
[]int{9, 8, 7},
}
for _, i := range ints {
fmt.Println(i)
}
}
Output[0 1 2]
[-1 -2 -3]
[9 8 7]
内部スライスの個々のアイテムにアクセスするために、ネストされたfor
ループを実装します。
main.go
package main
import "fmt"
func main() {
ints := [][]int{
[]int{0, 1, 2},
[]int{-1, -2, -3},
[]int{9, 8, 7},
}
for _, i := range ints {
for _, j := range i {
fmt.Println(j)
}
}
}
Output0
1
2
-1
-2
-3
9
8
7
ここでネストされたfor
ループを使用すると、スライスに含まれる個々のアイテムを反復処理できます。
結論
このチュートリアルでは、for
ループを宣言して使用し、Goで繰り返されるタスクを解決する方法を学びました。 また、for
ループの3つの異なるバリエーションと、それらをいつ使用するかについても学びました。 for
ループとそのフローを制御する方法の詳細については、Using Break and Continue Statements When Working with Loops in Goを参照してください。