콘텐츠로 이동

Rust for

for는 범위나 컬렉션의 항목을 하나씩 차례로 돌아요. Rust의 세 가지 반복문 중에서 가장 자주 쓰게 될 반복문이에요.

fn main() {
for i in 1..=5 {
println!("{i}");
}
}

실행 결과:

1
2
3
4
5
▶ 직접 실행해 보기

1..=5는 양쪽 끝을 모두 포함하는 범위(range)예요(1부터 5까지). =를 빼고 1..5라고 쓰면 하나 앞에서 멈춰서 1부터 4까지가 돼요. 이 하나 차이는 헷갈리기 쉬우니, 어느 쪽을 의도했는지 한 번 더 확인하는 게 좋아요.

for가 진짜 빛나는 곳은 바로 여기예요. 인덱스를 직접 관리하지 않고도 배열이나 벡터를 순회할 수 있어요.

fn main() {
let fruits = ["사과", "바나나", "체리"];
for fruit in fruits {
println!("{fruit}");
}
}

실행 결과:

사과
바나나
체리
▶ 직접 실행해 보기

while 반복문으로 직접 숫자를 세면서 인덱스(fruits[i])로 접근하는 방식과 비교해 보세요. 더 짧고, 틀릴 인덱스 자체가 없어요. 배열과 벡터는 배열 페이지와 벡터 페이지에서 더 자세히 배워요.

.enumerate()로 인덱스도 함께 얻기

섹션 제목: “.enumerate()로 인덱스도 함께 얻기”

위치와 값이 둘 다 필요하다면 .enumerate()를 쓰세요.

fn main() {
let fruits = ["사과", "바나나", "체리"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{index}: {fruit}");
}
}

실행 결과:

0: 사과
1: 바나나
2: 체리
▶ 직접 실행해 보기

(index, fruit) 부분은 튜플 패턴이에요. 반복할 때마다 한 쌍의 값이 나오고, 반복문이 그 쌍을 두 개의 변수로 나눠 줘요.

3부터 거꾸로 세고 싶거나, 숫자를 하나 걸러 하나씩만 보고 싶다면 어떻게 할까요? 처음에는 3..=1처럼 거꾸로 가는 범위를 떠올리기 쉬워요. 이 코드는 컴파일은 되지만 반복문이 한 번도 실행되지 않아요. 범위는 위로만 세기 때문에, 시작이 끝보다 큰 범위는 그냥 비어 있는 범위예요.

대신 평범한 범위를 만들고, 그 범위를 도는 방식을 바꿔요.

  • .rev()는 범위를 거꾸로 돌아요.
  • .step_by(n)은 첫 번째 값부터 시작해서 n번째마다 값을 하나씩 가져와요.
fn main() {
for i in (1..=3).rev() {
println!("{i}...");
}
println!("출발!");
for even in (0..=10).step_by(2) {
print!("{even} ");
}
println!();
for i in 3..=1 {
println!("이 줄은 출력되지 않아요: {i}");
}
}

실행 결과:

3...
2...
1...
출발!
0 2 4 6 8 10
▶ 직접 실행해 보기

괄호를 눈여겨보세요. (1..=3).rev()예요. 괄호가 없으면 Rust는 1..=3.rev()를 “1부터 3.rev()까지”로 읽는데, 이건 원하는 동작이 아니에요. 두 가지를 함께 쓸 수도 있어요. (0..=10).rev().step_by(5)는 10, 5, 0을 만들어요.

숫자를 셀 때 while보다 for를 쓰는 이유

섹션 제목: “숫자를 셀 때 while보다 for를 쓰는 이유”

숫자를 세는 반복문을 while로 쓸 수도 있어요. 하지만 범위와 함께 for를 쓰면 실수 하나가 통째로 사라져요. 깜빡하고 갱신하지 않을 카운터도 없고, 배열의 끝을 한 칸 넘어갈 위험도 없어요. Rust 프로그래머는 기본적으로 for를 쓰고, 순회할 범위나 컬렉션이 마땅히 없을 때만 while을 써요.

7 x 1 = 7부터 7 x 10 = 70까지 7단을 출력해 보세요. 힌트: 1..=10을 도는 for 반복문 하나면 충분해요. 곱셈은 println! 안에서 바로 할 수 있어요.

정답 보기
fn main() {
for i in 1..=10 {
println!("7 x {i} = {}", 7 * i);
}
}

실행 결과:

7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
▶ 직접 실행해 보기

{i}처럼 이름이 있는 변수는 중괄호 안에 바로 쓸 수 있어요. 하지만 7 * i 같은 계산식은 넣을 수 없어서, 빈 {}를 쓰고 쉼표 뒤에 값을 적어요.

1부터 99까지의 홀수를 모두 더해서 합계를 출력해 보세요. 힌트: (1..100).step_by(2)는 1, 3, 5, … 99를 만들어요. 합계를 담을 mut 변수는 반복문 바깥에 두세요.

정답 보기
fn main() {
let mut total = 0;
for n in (1..100).step_by(2) {
total += n;
}
println!("1부터 99까지 홀수의 합: {total}");
}

실행 결과:

1부터 99까지 홀수의 합: 2500
▶ 직접 실행해 보기

1..100을 돌면서 n % 2 == 1일 때만 n을 더하는 방법도 있어요. 둘 다 잘 동작해요. step_by는 숫자를 하나하나 검사하는 대신 짝수를 그냥 건너뛸 뿐이에요.

  • for item in 범위_또는_컬렉션 { ... }은 Rust에서 매일 쓰는 반복문이에요.
  • 1..=5는 양쪽 끝을 모두 포함하고, 1..5는 5 바로 앞에서 멈춰요.
  • 배열이나 벡터를 직접 순회하면 인덱스를 관리하지 않고도 각 값을 얻을 수 있어요.
  • 값과 함께 인덱스가 필요하면 .enumerate()를 쓰세요.
  • 3..=1 같은 거꾸로 된 범위는 비어 있어요. 거꾸로 셀 때는 (1..=3).rev()를, 건너뛰며 셀 때는 .step_by(n)을 쓰세요.

이해도 점검

1. for 반복문에서 1..=5와 1..5의 차이는 무엇일까요?

2. 컬렉션을 순회하면서 인덱스와 값을 함께 얻으려면 어떻게 할까요?

3. 컬렉션을 셀 때 보통 while보다 for를 더 선호하는 이유는 무엇일까요?

4. for i in 5..=1 { ... }은 어떻게 동작할까요?

점수: 0 / 4