Go에서 for range는 range 표현식의 값들에 대해 코드 블록을 반복해요.
range 표현식에 따라 각 반복이 값을 하나 반환할지 두 개 반환할지가 결정돼요.
슬라이스에 range를 사용하면 각 원소의 인덱스와 값을 순서대로 반환해요:
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(i, v)
}
// 0 10
// 1 20
// 2 30
맵에 range를 사용하면 각 키와 값을 반환하지만, 반복 순서는 보장되지 않아요.
Go는 맵의 반복 순서를 의도적으로 무작위화하기 때문에, 같은 프로그램이라도 실행할 때마다 다른 출력을 낼 수 있어요.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// 99 20
// 999 30
// 9 10
문자열에 range를 사용하면 바이트 인덱스와 각 룬(유니코드 코드 포인트)을 반환해요.
다음 예시에서 子는 3바이트를 차지하므로 猫는 바이트 인덱스 1이 아니라 3에서 시작해요.
for i, r := range "子猫" {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 3 29483 猫
룬 인덱스가 필요하다면, 문자열을 룬 슬라이스로 변환해요:
for i, r := range []rune("子猫") {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 1 29483 猫
range는 정수를 직접 순회할 수 있어요. 0부터 그 정수 직전까지의 값을 반환해요.
0과 음수도 유효하지만 반복은 하나도 일어나지 않아요.
for n := range 3 {
fmt.Println(n)
}
// 0
// 1
// 2
range는 iter.Seq[V] 또는 iter.Seq2[K, V] 타입의 이터레이터를 받아요.
이터레이터는 값을 한 번에 하나씩 만들어 내는 함수예요.
그러면 range가 그 값들을 하나씩 순회할 수 있어요.
text := "The quick brown fox"
for word := range strings.FieldsSeq(text) {
fmt.Println(word)
}
// The
// quick
// brown
// fox
names := []string{"Alice", "Bob", "Vera"}
for i, v := range slices.All(names) {
fmt.Println(i, ":", v)
}
// 0 : Alice
// 1 : Bob
// 2 : Vera
마지막으로, range는 채널로 전송된 값들을 다른 곳에서 그 채널이 닫힐 때까지 받을 수 있어요.
채널은 트랙 커리큘럼에서 나중에 더 자세히 다뤄요.
Go는 변수를 선언하고 사용하지 않으면 컴파일되지 않아요.
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(v)
}
// Go build failed: declared and not used: i
값만 필요하다면, 인덱스나 키를 _에 할당해서 무시해요.
vals := []int{10, 20, 30}
for _, v := range vals {
fmt.Println(v)
}
// 10
// 20
// 30
인덱스만 필요하다면, 값을 완전히 생략해요:
vals := []int{10, 20, 30}
for i := range vals {
fmt.Println(i)
}
// 0
// 1
// 2
인덱스도 값도 필요하지 않다면, 둘 다 생략할 수 있어요:
vals := []int{10, 20, 30}
count := 0
for range vals {
count++
}
// count == 3