開発者ドキュメント

GoでForループを構築する方法

序章

コンピュータプログラミングでは、 loop は、コードの一部を繰り返し実行するためにループするコード構造であり、多くの場合、何らかの条件が満たされるまで続きます。 コンピュータープログラミングでループを使用すると、同様のタスクを自動化して複数回繰り返すことができます。 処理する必要のあるファイルのリストがある場合、または記事の行数をカウントしたい場合を想像してみてください。 これらのタイプの問題を解決するには、コードでループを使用します。

Goでは、 for loopは、ループカウンターまたはループ変数に基づいてコードの繰り返し実行を実装します。 次のような複数のループ構造を持つ他のプログラミング言語とは異なり、 while, do、など、Goには for ループ。 これは、同じループ構造を実現するために複数の戦略を心配する必要がないため、コードをより明確で読みやすくするのに役立ちます。 この読みやすさの向上と開発中の認知的負荷の軽減により、コードは他の言語よりもエラーが発生しにくくなります。

このチュートリアルでは、Goがどのように for ループは、その使用法の3つの主要なバリエーションを含めて機能します。 まず、さまざまなタイプの作成方法を示します。 for ループし、続いてGoシーケンシャルデータ型をループする方法。 最後に、ネストされたループの使用方法について説明します。

ForClauseおよびConditionループの宣言

さまざまなユースケースを説明するために、作成する3つの異なる方法があります for Goのループで、それぞれに独自の機能があります。 これらは作成することです for Condition ForClause 、またはRangeClauseでループします。 このセクションでは、ForClauseおよびConditionバリアントを宣言して使用する方法について説明します。

使用方法を見てみましょう for 最初にForClauseでループします。

ForClauseループは、初期ステートメント条件後ステートメントの順であると定義されています。 これらは次の構文で配置されます。

for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
    [Action]
}

上記のコンポーネントが何をするかを説明するために、 for ForClause構文を使用して、指定された範囲の値をインクリメントするループ:

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 を使用して反復が発生するたびに1ずつ増加します i++ インクリメント演算子。

このプログラムを実行すると、出力は次のようになります。

Output
0 1 2 3 4

ループは5回実行されました。 最初に、それは設定しました i0、次にチェックして i 未満でした 5. の値以来 i 未満でした 5、実行されたループとのアクション fmt.Println(i) 実行されました。 ループが終了した後、 i++ と呼ばれ、の値 i 1ずつ増加しました。

注:プログラミングではインデックス0から開始する傾向があるため、5つの数値が出力されますが、0〜4の範囲であることに注意してください。

0から開始したり、指定した値で終了したりすることに限定されません。 最初のステートメントに任意の値を割り当てることができ、postステートメントの任意の値で停止することもできます。 これにより、ループスルーする任意の範囲を作成できます。

for i := 20; i < 25; i++ {
	fmt.Println(i)
}

ここでは、反復は20(包括的)から25(排他的)になるため、出力は次のようになります。

Output
20 21 22 23 24

postステートメントを使用して、さまざまな値でインクリメントすることもできます。 これはに似ています step 他の言語:

まず、正の値を持つpostステートメントを使用しましょう。

for i := 0; i < 15; i += 3 {
	fmt.Println(i)
}

この場合、 for ループは、0から15までの数字が出力されるように設定されていますが、3ずつ増加するため、次のように3つおきの数字のみが出力されます。

Output
0 3 6 9 12

postステートメントの引数に負の値を使用して逆方向に反復することもできますが、それに応じて最初のステートメントと条件の引数を調整する必要があります。

for i := 100; i > 0; i -= 10 {
	fmt.Println(i)
}

ここでは、 i 初期値に 100、の条件を使用します i < 0 に立ち寄る 0、およびpostステートメントは、値を10ずつ減らします。 -= オペレーター。 ループはで始まります 100 で終了します 0、反復ごとに10ずつ減少します。 これが出力で発生することがわかります。

Output
100 90 80 70 60 50 40 30 20 10

また、最初のステートメントと後のステートメントをから除外することもできます。 for 構文、および条件のみを使用します。 これは、条件ループとして知られているものです。

i := 0
for i < 5 {
	fmt.Println(i)
	i++
}

今回は変数を宣言しました i とは別に for コードの前の行でループします。 ループには、次のことを確認する条件句のみがあります。 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\ntwo\nthree\nfour\n") いくつかのデータを含むバッファを宣言します。 バッファがいつ読み取りを終了するかわからないため、次のように作成します。 for 句のないループ。 内部 for ループ、使用します line, err := buf.ReadString('\n') バッファから行を読み取り、バッファからの読み取り中にエラーが発生したかどうかを確認します。 存在する場合は、エラーに対処し、breakキーワードを使用してforループを終了します。 これ等と一緒に break ポイント、ループを停止するための条件を含める必要はありません。

このセクションでは、ForClauseループを宣言し、それを使用して既知の範囲の値を反復処理する方法を学習しました。 また、Conditionループを使用して、特定の条件が満たされるまで反復する方法も学びました。 次に、RangeClauseを使用してシーケンシャルデータ型を反復処理する方法を学習します。

RangeClauseを使用したシーケンシャルデータ型のループ

Goで使用するのが一般的です for スライス、配列文字列などのシーケンシャルまたはコレクションデータ型の要素を反復処理するためのループ。 これを簡単にするために、 for RangeClause構文でループします。 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])
	}
}

これを実行すると、次の出力が得られ、スライスの各要素が出力されます。

Output
hammerhead 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)
	}
}

この場合、リスト内の各アイテムを印刷しています。 変数を使用しましたが ishark、変数を他の有効な変数名と呼ぶことができ、同じ出力が得られます。

Output
0 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)
	}
}
Output
src/range-error.go:8:6: i declared and not used

なぜなら i で宣言されています for ループしますが、使用されることはありません。コンパイラは次のエラーで応答します。 i declared and not used. これは、変数を宣言して使用しない場合にGoで受け取るエラーと同じです。

このため、Goにはアンダースコアである空白の識別子があります(_). で 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)
	}
}
Output
hammerhead 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']

ここでは、のプレースホルダー文字列を追加しました "shark" の長さの各アイテムについて sharks スライス。

空白の識別子を使用する必要がなかったことに注意してください _ からの戻り値を無視する 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)
	}
}
Output
S a m m y

マップを反復処理する場合、 range キーの両方を返します。

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)
	}
}
Output
color: blue location: ocean name: Sammy animal: shark

注:マップが返される順序はランダムであることに注意することが重要です。 このプログラムを実行するたびに、異なる結果が得られる場合があります。

これで、シーケンシャルデータを反復処理する方法を学習しました。 range for ループ、ループ内でループを使用する方法を見てみましょう。

ネストされたForループ

ループは、他のプログラミング言語と同様に、Goでネストできます。 ネストは、ある構成が別の構成の中にある場合です。 この場合、ネストされたループは、別のループ内で発生するループです。 これらは、データセットのすべての要素に対してループアクションを実行する場合に役立ちます。

ネストされたループは、ネストされたifステートメントと構造的に類似しています。 それらは次のように構成されています。

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)
		}
	}
}

このプログラムを実行すると、次の出力が表示されます。

Output
1 a b c 2 a b c 3 a b c

出力は、プログラムが印刷によって外側のループの最初の反復を完了することを示しています 1、次に内部ループの完了をトリガーし、印刷します a, b, c 連続して。 内側のループが完了すると、プログラムは外側のループの先頭に戻り、次のように出力します。 2、次に再び内側のループ全体を印刷します(a, b, c)など。

ネスト for ループは、スライスで構成されるスライス内のアイテムを反復処理するのに役立ちます。 スライスで構成されるスライスで、1つだけを使用する場合 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 {
		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)
		}
	}
}
Output
0 1 2 -1 -2 -3 9 8 7

ネストされたものを使用する場合 for ここでループすると、スライスに含まれる個々のアイテムを反復処理できます。

結論

このチュートリアルでは、宣言と使用方法を学びました for Goで繰り返されるタスクを解決するためのループ。 また、3つの異なるバリエーションを学びました for ループとそれらをいつ使用するか。 詳細については for ループとそのフローを制御する方法については、Goでループを操作するときのBreakおよびContinueステートメントの使用をお読みください。

モバイルバージョンを終了