for 루프
for와 range
for in 구문은 Iterator를 통해 반복하는 데 사용될 수 있습니다. 이터레이터를 만드는 가장 쉬운 방법 중 하나는 범위 표기법 a..b를 사용하는 것입니다. 이는 a(포함)부터 b(미포함)까지의 값을 1씩 증가시키며 생성합니다.
while 대신 for를 사용하여 FizzBuzz를 작성해 봅시다.
fn main() {
// 각 반복에서 `n`은 1, 2, ..., 100의 값을 갖게 됩니다.
for n in 1..101 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
또는 양쪽 끝을 모두 포함하는 범위에는 a..=b를 사용할 수 있습니다. 위의 코드는 다음과 같이 작성될 수 있습니다:
fn main() {
// 각 반복에서 `n`은 1, 2, ..., 100의 값을 갖게 됩니다.
for n in 1..=100 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
for와 이터레이터
for in 구문은 여러 방식으로 Iterator와 상호작용할 수 있습니다. Iterator 트레이트 섹션에서 다룬 것처럼, 기본적으로 for 루프는 컬렉션에 into_iter 함수를 적용합니다. 하지만 이것이 컬렉션을 이터레이터로 변환하는 유일한 방법은 아닙니다.
into_iter, iter, iter_mut은 모두 내부 데이터에 대해 서로 다른 뷰를 제공함으로써 컬렉션을 이터레이터로 변환하는 작업을 서로 다른 방식으로 처리합니다.
iter- 매 반복마다 컬렉션의 각 요소를 빌려옵니다. 따라서 컬렉션은 수정되지 않은 상태로 유지되며 루프 이후에도 재사용할 수 있습니다.
fn main() {
let names = vec!["밥", "프랭크", "페리스"];
for name in names.iter() {
match name {
&"페리스" => println!("우리 중에 러스타시안(rustacean)이 있습니다!"),
// TODO ^ &를 삭제하고 그냥 "Ferris"와 매칭해 보세요
_ => println!("안녕 {}", name),
}
}
println!("이름들: {:?}", names);
}
into_iter- 컬렉션을 소비(consume)하여 각 반복마다 실제 데이터를 제공합니다. 컬렉션이 소비되면 루프 내에서 ’이동(moved)’된 것이므로 더 이상 재사용할 수 없습니다.
fn main() {
let names = vec!["밥", "프랭크", "페리스"];
for name in names.into_iter() {
match name {
"페리스" => println!("우리 중에 러스타시안(rustacean)이 있습니다!"),
_ => println!("안녕 {}", name),
}
}
println!("이름들: {:?}", names);
// FIXME ^ 이 줄을 주석 처리하세요
}
iter_mut- 컬렉션의 각 요소를 가변적으로 빌려와서, 컬렉션을 제자리에서 수정할 수 있게 합니다.
fn main() {
let mut names = vec!["밥", "프랭크", "페리스"];
for name in names.iter_mut() {
*name = match name {
&mut "페리스" => "우리 중에 러스타시안(rustacean)이 있습니다!",
_ => "안녕",
}
}
println!("이름들: {:?}", names);
}
위의 스니펫에서 match 분기의 타입에 주목하세요. 이것이 반복 방식의 핵심적인 차이점입니다. 타입의 차이는 물론 수행할 수 있는 작업의 차이를 의미합니다.