제어 흐름문
if 표현식과 loop·while·for 반복문을 사용하고 루프 라벨과 break 반환값으로 중첩 흐름을 제어합니다.
어떤 조건이 참인지에 따라 특정 코드를 실행하고, 어떤 조건을 만족하는 동안 특정 코드를 반복 수행하는 기능은 대부분의 프로그래밍 언어에서 기본 재료로 사용됩니다.
러스트 코드의 실행 흐름을 제어하도록 해주는 가장 일반적인 재료는 if 표현식과 반복문입니다.
if 표현식
if 표현식은 여러분의 코드가 조건에 따라 분기할 수 있도록 해줍니다.
조건을 제공한 뒤 다음과 같이 기술하는 식이죠.
‘만약 조건을 만족하면, 이 코드 블록을 실행하세요.’
‘그렇지 않다면 코드 블록을 실행하지 마세요.’
if 표현식을 알아보기 위해서 여러분의 projects 디렉터리에 branches라는 새 프로젝트를 생성합시다.
src/main.rs 파일에 다음을 입력하세요.
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
모든 if 표현식은 if라는 키워드로 시작하고 그 뒤에 조건이 옵니다.
위의 경우 조건은 변수 number가 5보다 작은 값인지 검사합니다.
조건이 참일 때 실행하는 코드 블록은 조건 바로 뒤 중괄호로 된 블록에 배치됩니다.
if 표현식의 조건과 관련된 코드 블록은 1장의 ‘비밀번호와 추릿값을 비교하기’절에서 다뤘던 match식의 갈래(arms) 와 마찬가지로 갈래로 불리기도 합니다.
추가로 위의 경우처럼 else 갈래를 붙일 수도 있는데, 이는 프로그램에게 해당 조건이 거짓일 경우 실행되는 코드 블록을 제공합니다.
else 갈래가 없고 조건식이 거짓이라면, 프로그램은 if 블록을 생략하고 다음 코드로 넘어갑니다. 이때 전체 if 표현식의 값은 유닛 타입 ()입니다.
이 코드를 실행해보면 다음과 같은 결과를 얻을 수 있습니다.
condition was truecargo run이 함께 표시하는 컴파일 상태, 실행 파일 경로, 소요 시간은 도구 버전과 환경에 따라 달라집니다. 이 장에서는 프로그램이 직접 출력한 줄만 제시합니다.
조건을 false로 만드는 값으로 number의 값을 변경하면 어떤 일이
일어나는지 봅시다.
let number = 7;
프로그램을 다시 실행시키면 다음과 같은 결과를 보게 됩니다.
condition was false또한 이 코드의 조건식이 반드시 bool 이어야 한다는 점을 주목할 가치가 있습니다.
조건식이 bool이 아니면 에러가 발생합니다.
예를 들자면 아래 코드를 실행해보세요.
fn main() {
let number = 3;
if number {
println!("number was three");
}
}
이 경우에는 if 조건식의 결과가 3이고, 러스트는 타입 불일치 오류를 발생시킵니다.
컴파일러는 일반적으로 E0308 타입 불일치 진단과 함께 조건에서 bool을 기대했지만 정수를 받았다고 알려줍니다. 진단의 문구, 경로와 줄 번호는 컴파일러 버전과 소스 위치에 따라 달라질 수 있습니다.
이 에러는 러스트가 bool을 예상했으나 정숫값을 받았다는 것을 알려줍니다.
Ruby나 JavaScript 같은 언어와 달리 러스트는 부울린 타입이 아닌 값을 부울린 타입으로 자동 변환하지 않습니다.
if문에는 항상 명시적으로 부울린 타입의 조건식을 제공해야 합니다.
예를 들어 어떤 숫자가 0이 아닌 경우에만 if 코드 블록을 실행시키고자 한다면, 다음과 같이 if 표현식을 바꾸면 됩니다.
fn main() {
let number = 3;
if number != 0 {
println!("number was something other than zero");
}
}
이 코드를 실행시키면 number was something other than zero가 출력될 것입니다.
else if로 여러 조건식 다루기
if와 else 사이에 else if를 조합하면 여러 조건식을 사용할 수 있습니다.
예를 들면.
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
이 프로그램은 분기 가능한 4개의 경로가 있습니다.
실행하면 다음과 같은 결과를 보게 됩니다.
number is divisible by 3이 프로그램을 실행하면 각각의 if 표현식을 순차적으로 검사하고 조건이 참일 때의 첫 번째 본문을 실행합니다.
6이 2로 나누어 떨어지지만 number is divisible by 2나 number is not divisible by 4, 3, or 2와 같은 else 블록의 텍스트가 출력되지 않는다는 점을 주목하세요.
이는 러스트가 처음으로 true인 조건의 본문을 실행하고나면 나머지는 검사도 하지 않기 때문입니다.
else if 표현식을 너무 많이 사용하면 코드가 복잡해질 수 있으므로, 표현식이 두 개 이상이면 코드를 리팩터링하는 것이 좋습니다.
6장에서는 이런 경우에 적합한 match라는 러스트의 강력한 분기 구조에 대해 설명합니다.
let 구문에서 if 사용하기
if는 표현식이기 때문에 예제 2-2처럼 변수에 결과를 할당하기
위하여 let 구문의 우변에 사용할 수 있습니다.
if 표현식의 결과를 변수에
할당하기
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
변수 number에는 if 표현식을 계산한 결괏값이 바인딩될 것입니다.
코드를 실행해서 무슨 일이 벌어지는지 봅시다.
The value of number is: 5코드 블록은 블록 안의 마지막 표현식을 계산하고, 숫자는 그 자체로 표현식임을 기억하세요.
위의 경우 전체 if 표현식의 값은 실행되는 코드 블록에 따라 결정됩니다.
그렇기에 if 표현식의 모든 실행 경로는 하나의 공통 타입으로 결정되어야 합니다.
예제 2-2에서 if 갈래와 else 갈래는 모두 i32 정숫값입니다.
갈래의 소스 타입이 글자 그대로 같아야 한다는 뜻은 아닙니다. 러스트는 갈래 사이에 허용되는 타입 강제 변환(coercion)을 적용해 공통 타입을 찾습니다. 예를 들어 한 갈래의 &String이 &str로 강제 변환되어 다른 갈래의 문자열 슬라이스와 호환될 수 있습니다.
하지만 만약 다음 예제처럼 타입이 다르면 어떻게 될까요?
fn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {number}");
}
이 코드를 컴파일하려고 하면 에러가 발생합니다.
if와 else 갈래 값의 타입이 호환되지 않고, 러스트는 프로그램의 어느 지점에 문제가 있는지 정확히 알려줍니다.
컴파일러는 일반적으로 E0308 타입 불일치 진단으로 두 갈래의 타입이 호환되지 않는 위치를 가리킵니다. 정확한 진단 문구와 위치 표시는 컴파일러 버전과 소스에 따라 달라질 수 있습니다.
if 블록은 정숫값을 계산하는 표현식이고 else 블록은 문자열로 평가되는 표현식입니다.
이런 형태의 코드가 동작하지 않는 이유는 변수가 가질 수 있는 타입이 오직 하나이기 때문입니다.
러스트는 컴파일 시점에 number 변수의 타입이 무엇인지 확실히 알 필요가 있습니다.
그래야 컴파일 시점에 number가 사용되는 모든 곳에서 해당 타입이 유효한지 검증할 수 있으니까요.
러스트에서는 number의 타입이 런타임에 정의되도록 할 수 없습니다; 컴파일러가 어떤 변수에 대해 여러 타입에 대한 가정값을 추적해야 한다면 컴파일러는 더 복잡해지고 보장할 수 있는 것들이 줄어들 것입니다.
아래 다이어그램은 if 표현식을 값으로 사용할 때 조건, 갈래의 꼬리 표현식, 공통 타입과 생략된 else의 () 계약을 한 번에 비교합니다.
IF EXPRESSION CONTRACT
실행 경로는 하나지만 컴파일러는 모든 경로에서 하나의 결과 타입을 확정한다.
| 검사 지점 | 언어 계약 | 코드에서 확인할 것 | 대표 결과 |
|---|---|---|---|
| 조건 | 이 절의 일반 조건식은 반드시 bool이다. 조건부 let 매치는 별도 조건 형식이다. |
if number != 0처럼 의도를 명시한다. 일반 정수식을 참·거짓으로 바꾸지 않는다. |
true인 첫 갈래만 실행한다. |
| 선택된 블록 | 전체 if의 값은 실제로 실행된 블록의 값이다. |
블록의 꼬리 표현식은 세미콜론 없이 값을 내보낸다. 세미콜론으로 끝나면 보통 ()가 된다. |
{ 5 } → 5; { 5; } → () |
| 모든 갈래 | 각 갈래의 결과는 강제 변환을 포함해 하나의 공통 타입으로 결정되어야 한다. | 소스 타입이 글자 그대로 같지 않아도 허용된 coercion으로 공통 타입을 만들 수 있다. | &String과 &str → 공통 &str 가능; i32와 &str → 호환 불가 |
else 생략 |
아무 블록도 실행되지 않는 경로의 값은 ()이므로 전체 결과도 ()여야 한다. |
효과만 수행하는 if에는 자연스럽지만, 임의의 값을 만들려면 호환되는 else가 필요하다. |
if ready { notify(); } → () |
let 우변 |
선택된 값 하나가 추론된 공통 타입의 바인딩을 만든다. | 런타임 조건은 어떤 값을 고를지만 결정하고 변수의 타입을 바꾸지 않는다. | let n = if ok { 5 } else { 6 }; → n: i32 |
- 1. 조건은
bool - 계약 이 절의 일반 조건식은 반드시
bool입니다. 조건부let매치는 별도 형식이며, 일반 정수식을 참·거짓으로 바꾸지 않습니다. - 확인
if number != 0처럼 의도를 명시하고, 첫 번째로 참인 갈래만 실행합니다. - 2. 선택된 블록이 값을 만든다
- 계약 전체
if는 실제로 실행된 블록의 값으로 평가됩니다. - 확인
{ 5 }의 꼬리 표현식은5이고,{ 5; }처럼 세미콜론으로 끝나면 보통()입니다. - 3. 모든 갈래는 공통 타입
- 계약 갈래 결과는 허용된 강제 변환까지 적용해 하나의 공통 타입으로 결정되어야 합니다.
- 예
&String과&str은 공통&str이 될 수 있지만,i32와&str은 호환되지 않습니다. - 4.
else가 없으면() - 계약 아무 블록도 실행되지 않는 경로가
()이므로 전체 결과도()여야 합니다. - 선택 효과만 수행할 때는 자연스럽지만 임의의 값을 만들려면 호환되는
else가 필요합니다. - 5.
let에는 타입 하나 - 계약 선택된 값이 추론된 공통 타입의 바인딩을 만듭니다.
- 예
let n = if ok { 5 } else { 6 };에서 런타임 조건은 값을 고를 뿐n: i32를 바꾸지 않습니다.
반복문을 이용한 반복
코드 블록을 반복 수행하는 일은 자주 쓰입니다. 반복문의 종류와 입력 상태에 따라 본문은 한 번도 실행되지 않을 수도 있습니다.
반복 작업을 위해서, 러스트는 몇 가지 반복문(loop) 을 제공하는데 이는 루프 본문의 시작부터 끝까지 수행한 뒤 다시 처음부터 수행합니다.
반복문을 실험해보기 위해 loops라는 이름의 새 프로젝트를 만듭시다.
러스트에는 loop, while, 그리고 for라는 세 종류의 반복문이 있습니다.
하나씩 써봅시다.
loop로 코드 반복하기
loop 키워드는 여러분이 그만두라고 명시적으로 알려주기 전까지, 혹은 영원히
코드 블록을 반복 수행하도록 해줍니다.
일례로 loops 디렉터리의 src/main.rs 코드를 다음과 같이 바꿔보세요.
fn main() {
loop {
println!("again!");
}
}
이 프로그램을 실행시키면, 우리가 프로그램을 강제로 정지시키기 전까지 again!이 계속 반복적으로 출력되는 것을 보게 됩니다.
대부분의 터미널은 단축키 ctrl-c를 눌러서 무한루프에 빠진 프로그램을 정지시키는 기능을 지원합니다.
한번 시도해보세요.
again!
again!
again!
again!
^Cagain!기호 ^C는 우리가 ctrl-c를 누른 지점을 표시합니다.
코드가 정지 신호를 받은 시점에 따라 ^C 이후에 again!이 출력될 수도 안될 수도 있습니다.
다행히 러스트에서는 코드를 사용하여 루프에서 벗어나는 방법도 제공합니다.
루프 안에 break 키워드를 집어넣으면 루프를 멈춰야 하는 시점을 프로그램에게 알려줄 수 있습니다.
1장의 ‘정답을 맞힌 후 종료하기’절의 추리 게임 코드에서 사용자가 정답을 추리하여 게임에서 이겼을 경우 프로그램을 종료하기 위해 했었던 일을 상기해보세요.
추리 게임에서는 continue도 사용했었는데, 이는 프로그램에게
이번 회차에서 루프에 남은 코드를 넘겨버리고 다음 회차로 넘어가라고
알려줍니다.
반복문에서 값 반환하기
loop의 용례 중 하나는 어떤 스레드가 실행 완료되었는지 검사하는 등 실패할지도 모르는 연산을 재시도할 때입니다.
여기서 해당 연산의 결과를 이후의 코드에 전달하고 싶을 수도 있습니다.
이를 위해서는 루프 정지를 위해 사용한 break 표현식 뒤에 반환하고자 하는 값을 넣으면 됩니다. 해당 값은 아래와 같이 반복문 밖으로 반환되어 사용할 수 있습니다.
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}
반복문 전에 counter라는 이름의 변수를 선언하여 0으로 초기화 했습니다.
그 다음 result라는 변수를 선언하여 반복문으로부터 반환된 값을 저장하도록 했습니다.
반복문의 매 회차 마다 counter 변수에 1을 더한 후 값이 10과 같은지 검사합니다.
그런 경우 break 키워드와 counter * 2 값을 사용하였습니다.
루프 뒤에는 result에 값을 할당하는 구문을 끝내기 위해 세미콜론을 붙였습니다.
결과적으로 result의 값이 20으로 출력됩니다.
루프 라벨로 여러 반복문 사이에 모호함 없애기
만일 루프 안에 루프가 있다면, break와 continue는 해당 지점의 바로 바깥쪽 루프에 적용됩니다.
loop, while, for에 루프 라벨(loop label) 을 추가하면 break나 continue가 바로 바깥쪽 반복문 대신 라벨이 적힌 특정 반복문에 적용되도록 할 수 있습니다. 단, 값을 동반한 break 값으로 일반적인 반복문 밖에 값을 내보낼 수 있는 것은 loop입니다.
루프 라벨은 반드시 작은 따옴표로 시작해야 합니다.
아래에 루프가 두 개 중첩된 예제가 있습니다.
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
바깥쪽 루프는 'counting_up 이라는 라벨이 붙어있고, 0에서부터 2까지 카운트합니다.
라벨이 없는 안쪽 루프는 10에서 9까지 거꾸로 카운트합니다.
라벨이 명시되지 않은 첫 번째 break는 안쪽 루프만 벗어납니다.
break 'counting_up; 구문은 바깥쪽 루프를 탈출할 것입니다.
이 코드는 다음을 출력합니다.
count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2
while을 이용한 조건 반복문
반복문 내에서 조건을 검사하는 작업도 자주 사용됩니다.
조건문이 true인 동안에는 계속 반복하는 형태죠.
조건이 true가 아니게 되면 본문을 실행하지 않고 while 다음 문장으로 이어집니다.
이러한 반복문 형태는 loop, if, else와 break의 조합으로 구현할 수 있습니다; 여러분이 원하신다면 그렇게 시도해볼 수 있습니다.
하지만 이러한 패턴은 매우 흔하기 때문에 러스트에서는 while 반복문이라 일컫는 구조가 내장되어 있습니다.
예제 2-3은 while을 사용하여 코드를 3번 반복 실행하면서 매번 카운트를 깎고 난 다음, 반복문 후에 다른 메시지를 출력하고 종료합니다.
while 반복문을 사용하여 조건이 참인
동안 코드를 반복 실행하기
fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}
이 구조는 loop, if, else 및 break를 사용할 때 필요하게 될 많은 중첩 구조를 제거하고 코드를 더 깔끔하게 만듭니다.
조건식이 true로 계산되는 동안 코드가 실행되고, 그렇지 않으면 반복문을 벗어납니다.
조건 자리에 패턴을 사용하는 while let PATTERN = EXPRESSION도 있습니다. 표현식을 다시 평가할 때마다 패턴이 맞으면 새 바인딩으로 본문을 실행하고, 맞지 않으면 반복을 끝냅니다. 예를 들어 while let Some(value) = values.pop()은 Some이 나오는 동안 요소를 처리합니다.
for를 이용한 컬렉션에 대한 반복문
while을 사용하여 배열과 같은 컬렉션의 각 요소에 대한 반복문을 작성할 수 있습니다.
한 가지 예로 예제 2-4의 반복문은 a라는 배열의 각 요소를 출력합니다.
while 반복문을 사용하여 컬렉션의
각 요소 순회하기
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}
위의 코드는 배열의 요소들을 훑기 위해 숫자를 셉니다.
인덱스 0을 시작으로 배열의 마지막 인덱스에 도달할 때까지 반복합니다(위의 경우 index < 5가 true가 아닐때까지 입니다).
이 코드를 실행하면 배열의 모든 요소가 출력될 것입니다.
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50
기대한대로 배열의 다섯 개의 값이 모두 터미널에 출력됩니다 index가
어떤 시점에서 5에 도달하더라도 반복문은 이 배열로부터 6번째 값을
얻어오기 전에 실행 종료됩니다.
하지만 이런 접근 방식은 에러가 발생하기 쉽습니다; 즉 인덱스의 길이가 부정확하면 패닉을 발생시키는 프로그램이 될 수 있습니다.
예를 들어, a 배열이 네 개의 요소를 갖도록 정의 부분을 변경했는데 while index < 4의 조건문을 고치는걸 잊어버린다면 코드는 패닉을 일으킬 것입니다.
좀 더 간편한 대안으로 for 반복문을 사용하여 컬렉션의 각 아이템에 대하여 임의의 코드를 수행시킬 수 있습니다.
for 반복문은 예제 2-5의 코드처럼 생겼습니다.
for 반복문을 이용하여 컬렉션의
각 요소 순회하기
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}
이 코드를 실행하면 예제 2-4의 결과와 동일한 결과를 보게 됩니다.
그보다 더 중요한 것은 이렇게 함으로써 코드의 안전성이 강화되고 배열의 끝을 넘어서거나 끝까지 가지 못해서 몇 개의 아이템을 놓쳐서 발생할 수도 있는 버그의 가능성을 제거했다는 것입니다.
for PATTERN in expression은 expression에 IntoIterator::into_iter를 적용해 얻은 요소를 차례로 패턴에 바인딩합니다. 따라서 소유권은 반복 대상 식에 따라 달라집니다. 예를 들어 for item in items는 Vec<T> 같은 소유 컬렉션을 소비할 수 있고, 반복 뒤에도 컬렉션을 사용하려면 보통 for item in &items로 공유 빌림하거나 for item in &mut items로 가변 빌림합니다.
for 루프를 사용하면 여러분이 배열 내 값의 개수를
변경시키더라도 수정해야 할 다른 코드를 기억해둘 필요가
없어질 겁니다.
이러한 안전성과 간편성 덕분에 for 반복문은 러스트에서 가장 흔하게 사용되는 반복문 구성요소가 되었습니다.
심지어 while 반복문을 사용했던 예제 2-3의 카운트다운 예제처럼 어떤 코드를 몇 번 정도 반복하고 싶은 경우라도, 대부분의 러스타시안들은 for 반복문을 이용할 겁니다.
정수 범위처럼 반복 가능한 범위를 이용하면 특정 횟수만큼 반복할 수 있습니다. start..end는 start를 포함하고 end를 제외하며, start..=end는 양 끝을 포함합니다.
for 반복문을 이용한 카운트다운 구현은 아래처럼 생겼습니다.
여기서 아직 살펴보지 않았던 rev 메서드는 양방향으로 진행할 수 있는 반복자의 진행 순서를 뒤집습니다.
fn main() {
for number in (1..4).rev() {
println!("{number}!");
}
println!("LIFTOFF!!!");
}
이 코드가 좀 더 괜찮죠?
아래 다이어그램은 반복문 선택 기준을 포함해 조건 분기와 각 반복 형식을 진입 조건·종료·결괏값·소유권 관점에서 한 번에 비교합니다.
CONTROL-FLOW CHOOSER
분기인가 반복인가를 먼저 나눈다. 대상 집합은 for, 상태 조건은 while, 패턴 성공은 while let, 명시적 종료와 결과값은 loop가 출발점이다.
if· 경로 하나 선택- 진입 일반
bool식이나 조건부let매치를 순서대로 평가해 첫 번째로 맞는 갈래 하나를 실행합니다. - 종료·값 선택된 블록의 값을 내보내며 모든 경로는 강제 변환을 포함해 공통 타입이어야 합니다.
- 데이터·소유권 반복자를 만들지 않으며 각 갈래의 이동과 빌림 규칙이 그대로 적용됩니다.
- 선택 한 시점에 실행할 경로 하나를 고를 때 사용합니다.
loop· 본문이 종료 결정- 진입 사전 조건 없이 본문에 들어가 계속 반복합니다.
- 종료·값 연결된
break로 끝냅니다. 일반 반복문 중break expr로 유닛이 아닌 값을 내보낼 수 있는 형식입니다. - 데이터·소유권 대상 집합을 자동으로 소비하지 않으며 본문이 상태와 자원을 직접 다룹니다.
- 선택 재시도처럼 종료 시점이 본문 안에 있거나 결과를 반환할 때 사용합니다.
while condition· 상태 조건- 진입 매 회차 전에
bool조건을 검사하므로 0회 실행할 수 있습니다. - 종료·값 거짓이면 본문을 실행하지 않고 다음 문장으로 이어지며 결과는
()입니다. - 데이터·소유권 조건과 본문이 갱신하는 상태를 직접 관리합니다.
- 선택 남은 시간이나 큐 상태처럼 불리언 조건이 반복 여부를 정할 때 사용합니다.
while let PAT = expr· 패턴 조건- 진입 식을 다시 평가하고 패턴이 맞을 때만 새 바인딩으로 본문을 실행합니다.
- 종료·값 패턴이 맞지 않으면 다음 문장으로 이어지며 결과는
()입니다. - 데이터·소유권 식의 이동·빌림이 매 검사에 적용되고 새 바인딩은 조건 뒤 본문 범위에서 사용합니다.
- 선택
pop()의Some처럼 같은 패턴이 성공하는 동안 처리할 때 사용합니다. for PAT in expr· 대상 집합- 진입
IntoIterator::into_iter(expr)가 만든 반복자에서 요소가 나올 때마다 패턴에 바인딩합니다. - 종료·값 반복자가 비면 끝나며 결과는
()입니다. - 데이터·소유권
items는 소비할 수 있고&items는 공유 빌림,&mut items는 가변 빌림입니다. - 선택 컬렉션·반복자·범위처럼 대상 집합이 있을 때 사용합니다. 정수에서
a..b는b를 제외하고a..=b는 포함합니다.
break와 continue는 가장 안쪽 반복문을 대상으로 합니다. 'outer: 같은 라벨은 중첩된 loop·while·while let·for에서 목표를 명시합니다.개념 점검
해냈군요!
정말 긴 장이었습니다.
여러분은 변수, 스칼라 타입 및 복합 타입, 함수, 주석, if 표현식, 그리고 루프에 대해 배웠습니다!
이 장에서 다룬 개념들을 연습하고 싶다면 아래 프로그램 만들기에 도전해보세요.
- 화씨 온도와 섭씨 온도 간 변환하기
- n번째 피보나치 수 생성하기
- 크리스마스 캐롤 ‘The Twelve Days of Christmas’ 노래의 반복성을 활용하여 가사 출력해보기
다음으로 넘어갈 준비가 되셨다면, 이번에는 다른 프로그래밍 언어에는 흔치 않은 러스트의 개념인 소유권(ownership)에 대해 알아보겠습니다.