// 整数のスライスを作成して値を設定する
slice := []int{10, 20, 30, 40}
// 各要素を反復し、その値を表示する
for index, value := range slice {
fmt.Printf("インデックス: %d 値: %d\n", index, value)
}
4 行目のインデックスと値は、range キーワードによって返されるスライス内の各要素のインデックスと値を受け取るためにそれぞれ使用されます。ここでのインデックスと値は固定されておらず、リーダーは他の名前を定義することもできます。
forの詳しい使い方は次章「 Go言語のプロセス制御」で詳しく紹介します。
上記のコードの出力は次のとおりです。
Index: 0 Value: 10
Index: 1 Value: 20
Index: 2 Value: 30
Index: 3 Value: 40
次の図に示すように、スライスを反復する場合、キーワード range は 2 つの値を返します。最初の値は現在反復されているインデックス位置で、2 番目の値はその位置に対応する要素値のコピーです。
以下に示すように、range は各要素への参照を直接返すのではなく、各要素のコピーを返すことを強調することが重要です。
[例 1] range は各要素のコピーを提供します
// 整数のスライスを作成して値を割り当てる
slice := []int{10, 20, 30, 40}
// 各要素を繰り返して、値とアドレスを表示する
for index, value := range slice {
fmt.Printf("値: %d 値のアドレス: %X 要素のアドレス: %X\n", value, &value, &slice[index])
}
出力は次のとおりです。
Value: 10 Value-Addr: 10500168 ElemAddr: 1052E100
Value: 20 Value-Addr: 10500168 ElemAddr: 1052E104
Value: 30 Value-Addr: 10500168 ElemAddr: 1052E108
Value: 40 Value-Addr: 10500168 ElemAddr: 1052E10C
反復によって返される変数は、反復処理中にスライスに従って順次割り当てられる新しい変数であるため、値のアドレスは常に同じです。各要素のアドレスを取得するには、スライス変数とインデックス値 (たとえば、上記のコードでは、&slice[index])。
インデックス値が必要ない場合は、アンダースコア_
を使用してこの値を無視することもできます。コードは次のとおりです。
[例 2] 空白の識別子 (アンダースコア) を使用してインデックス値を無視する
// 整数のスライスを作成し、値を割り当てる
slice := []int{10, 20, 30, 40}
// 各要素を反復処理し、その値を表示する
for _, value := range slice {
fmt.Printf("Value: %d\n", value)
}
出力は次のとおりです。
Value: 10
Value: 20
Value: 30
Value: 40
キーワード範囲は常にスライス ヘッダーから反復されます。反復をさらに制御したい場合は、従来の for ループを使用できます。コードを以下に示します。
[例 3] 従来の for ループを使用してスライスを反復処理する
// 整数のスライスを作成し、値を割り当てる
slice := []int{10, 20, 30, 40}
// 3番目の要素から要素を反復処理する
for index := 2; index < len(slice); index++ {
fmt.Printf("Index: %d Value: %d\n", index, slice[index])
}
出力は次のとおりです。
Index: 2 Value: 30
Index: 3 Value: 40
前のセクションの学習で、配列、スライス、チャネルの処理に使用できる 2 つの特別な組み込み関数 len() と cap() について学びました。スライスの場合、関数 len() は長さを返すことができます。関数 cap() はスライスの容量を返すことができます。上記の例では、関数 len() を使用してループの反復数を制御しています。
もちろん、 range キーワードはスライスの走査に使用できるだけでなく、配列、文字列、マップ、チャネルなどの走査にも使用できます。これについては後の研究で詳しく紹介します。