hyunsu blog

홈강좌Rust 입문·중급 47편 중 14편째

Rust for 와 범위 — 배열과 0..n 을 처음부터 끝까지 돈다

목차 · 3
  1. 01배열을 처음부터 끝까지
  2. 02범위 — 0..n 과 1..=n
  3. 03실습 — n번째 피보나치 수

Rust 의 for 는 배열이나 범위의 값을 하나씩 꺼내 되풀이한다. 0..3 은 0·1·2, 1..=3 은 1·2·3 이고, .rev() 를 붙이면 거꾸로 돈다. 번호를 직접 세지 않으니 범위를 벗어날 일이 없어서, 정해진 만큼 돌 때는 for 가 기본이다.

01 배열을 처음부터 끝까지

9편의 점수 배열을 하나씩 찍어 보자.

rust
fn main() {
    let scores = [72, 85, 90];

    for score in scores {
        println!("{score}");
    }
}
text
   Compiling scores v0.1.0 (~/projects/scores)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/scores`
72
85
90

for score in scores 는 "scores 의 값을 하나씩 꺼내 score 에 담고 중괄호 안을 실행하라" 는 뜻이다. 값을 다 꺼내면 저절로 끝난다. 번호 변수도, 끝 조건도, break 도 필요 없다.

13편의 while 로 scores[i] 를 돌면 i 를 늘리는 줄을 빠뜨리거나 끝 번호를 잘못 써서 9편의 범위 밖 패닉을 낼 수 있다. for 는 그럴 일이 없다.

02 범위 — 0..n 과 1..=n

숫자를 차례로 돌 때는 범위를 쓴다.

rust
fn main() {
    for i in 0..3 {
        println!("0..3 -> {i}");
    }

    for i in 1..=3 {
        println!("1..=3 -> {i}");
    }

    for i in (1..=3).rev() {
        println!("rev -> {i}");
    }
}
text
   Compiling ranges v0.1.0 (~/projects/ranges)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/ranges`
0..3 -> 0
0..3 -> 1
0..3 -> 2
1..=3 -> 1
1..=3 -> 2
1..=3 -> 3
rev -> 3
rev -> 2
rev -> 1
범위뜻값
0..30 부터 3 바로 앞까지0, 1, 2
1..=31 부터 3 까지1, 2, 3
(1..=3).rev()거꾸로3, 2, 1

0..n 은 정확히 n 번 돈다. 0 부터 세는 배열 번호와 잘 맞는다. 끝 숫자까지 넣고 싶으면 ..= 를 쓴다. .rev() 는 범위를 뒤집는 메서드다.

1 부터 100 까지 더하는 것도 범위로 바로 쓴다.

rust
fn main() {
    let mut total = 0;
    for n in 1..=100 {
        total = total + n;
    }
    println!("{total}");
}
text
   Compiling sum v0.1.0 (~/projects/sum)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
     Running `target/debug/sum`
5050

03 실습 — n번째 피보나치 수

피보나치 수는 앞의 두 수를 더해 다음 수를 만든다(0, 1, 1, 2, 3, 5, 8, …). 두 수 a·b 를 들고 n 번 앞으로 나아가면 a 가 n번째 수다.

rust
fn fib(n: u32) -> u64 {
    let mut a = 0;
    let mut b = 1;
    for _ in 0..n {
        let next = a + b;
        a = b;
        b = next;
    }
    a
}

fn main() {
    for n in [1, 2, 10, 50] {
        let value = fib(n);
        println!("fib({n}) = {value}");
    }
}
text
   Compiling fib v0.1.0 (~/projects/fib)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/fib`
fib(1) = 1
fib(2) = 1
fib(10) = 55
fib(50) = 12586269025
  • for _ in 0..n 은 n 번 돈다. 꺼낸 값을 쓰지 않으니 이름 자리에 _ 를 둔다.
  • fib(50) 은 120억이 넘어서 i32(약 21억까지, 5편)에는 안 들어간다. 그래서 반환 타입을 u64 로 했다.
  • 함수 마지막 줄 a 에는 세미콜론이 없다. 이 값이 반환값이다(11편).

여기까지 함수·if·for 를 모두 쓰면, 11편의 온도 변환을 여러 온도에 한꺼번에 돌릴 수 있다.

rust
fn to_fahrenheit(c: f64) -> f64 {
    c * 9.0 / 5.0 + 32.0
}

fn main() {
    for c in [10.0, 25.0, 35.0] {
        let f = to_fahrenheit(c);
        let note = if f >= 86.0 { "덥다" } else { "선선하다" };
        println!("{c}℃ = {f}℉ {note}");
    }
}
text
   Compiling convert v0.1.0 (~/projects/convert)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/convert`
10℃ = 50℉ 선선하다
25℃ = 77℉ 선선하다
35℃ = 95℉ 덥다

[10.0, 25.0, 35.0] 배열을 for 로 돌면서 함수를 부르고, if 로 낸 말을 찍었다. 이것으로 기본 문법이 끝났다. 다음 편부터는 Rust 를 다른 언어와 가르는 개념, 소유권을 다룬다.