다른 프로그래밍 언어가 대부분 가진 개념이 Rust에서 어떻게 다루어지는지 확인
그 중 제어문에 대한 이야기
실행 흐름을 제어할 수 있는 가장 보편적인 작성 방식은 if 표현식과 반복문이다.
if
표현식은 우리가 조건에 따라 분기할 수 있게 해준다.
if를 한국어로 만약이라는 뜻과 같이 "만약 조건이 충족하면, 다음 코드를 실행하라"와 같은 실행 흐름을 제어할 수 있게 된다.
다음은 예시 코드이다.
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
위처럼 if
표현식은 if라는 키워드로 시작하고 조건이 나온다.
위 코드의 결과는 다음과 같다.
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/branches`
condition was true
다음 코드는 타입에 대한 주의점을 알려준다.
fn main() {
let number = 3;
if number {
println!("number was three");
}
}
위 코드를 실행하면 아래와 같은 오류를 확인할 수 있다.
error[E0308]: mismatched types
--> src/main.rs:4:8
|
4 | if number {
| ^^^^^^ expected bool, found integral variable
|
= note: expected type `bool`
found type `{integer}`
위 에러는 Rust가 bool
형식을 기대하였으나 정수형이 왔다는 내용이고 Rust는 Ruby나 JS와 같이 자동으로 변환해주지 않는다.
만약 정수형으로 조건을 하고 싶은 경우에는 아래와 같이 작업이 가능하다.
fn main() {
let number = 3;
if number != 0 {
println!("number was something other than zero");
}
}
이번에는 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가지의 조건이 존재하고 아래와 같은 결과가 나타날 것이다.
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/branches`
number is divisible by 3
위 스크립트에서 봐야할 중요한 사항으로 6이라는 값이 2로 나누어 떨어짐에도 불구하고, number is divisible by 2
라는 값이 출력되지 않는다는 점이다.
이렇게 되는 이유는 Rust가 첫 번째로 조건이 참이 되는 블록만 찾아 실행하고, 만약 찾게 된다면 나머지는 검색하지 않기 때문이다.
위에서 보면 if
표현식이라고 말하는 것 처럼 if
가 표현식이기 때문에 이를 let
구문의 우측에 사용할 수 있다.
다음은 예시이다.
fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};
println!("The value of number is: {}", number);
}
위 코드에서 변수 number
에는 if 표현식에서 산출된 값이 bound 된다.
다음은 결과이다.
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/branches`
The value of number is: 5
여기서 주의해야 할 점은 if
표현식의 갈래 부분 즉 if 부분과 else 부분식의 각 갈래의 결과는 반드시 같은 타입이여야 한다.
예제로 다음의 코드를 확인해보자.
fn main() {
let condition = true;
let number = if condition {
5
} else {
"six"
};
println!("The value of number is: {}", number);
}
위 코드에서는 조건이 참일경우 정수형, 참이 아닌 경우 문자형을 표현하는데 이렇게 다른 타입을 결과로 출력할 경우 아래와 같은 오류를 확인할 수 있다.
error[E0308]: if and else have incompatible types
--> src/main.rs:4:18
|
4 | let number = if condition {
| __________________^
5 | | 5
6 | | } else {
7 | | "six"
8 | | };
| |_____^ expected integral variable, found reference
|
= note: expected type `{integer}`
found type `&str`
코드 블록을 한 번 이상 수행하는 것은 자주 사용된다. 반복되는 작업을 위해, Rust는 3가지를 지원한다.(loop
, while
, for
)
loop
키워드는 Rust에게 그만두라고 명시하기 전까지 코드 블럭을 반복적으로 수행한다.
예시는 다음과 같다.
fn main() {
loop {
println!("again!");
}
}
위 코드를 실행하면 강제로 정지하기 전까지 again!
이라는 문자열이 반복 출력하게 된다.
ctrl-C 키를 통해서 무한 루프를 탈출할 수 있다.
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!
또한 break를 사용하여 탈출할 수 있다.
반복문에서 조건이 참이 아니게 된 경우에 break를 호출하여 반복을 정지시킨다.
이런 패턴의 반복문을 구현하면 loop
, if
, else
, break
를 혼합해서 사용해야 한다.
하지만 위와 같은 동일한 구조체가 존재하는데 이것이 바로 while
키워드이다.
다음 예시는 while 키워드의 예시이다.
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number = number - 1;
}
println!("LIFTOFF!!!");
}
위 코드는 조건이 true인 동안 코드가 실행되고 그렇지 않으면 루프에서 벗어나게 된다.
코드를 작성하다 보면 다음과 같은 코드가 필요할 때가 있다.
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index = index + 1;
}
}
위 코드에서 배열의 요소에 걸쳐서 카운트를 증가한다. index는 0부터 시작하고, 배열의 마지막 즉 5번째인 50 까지 반복된다. 이 코드를 수행하면 배열의 모든 요소가 출력되게 한다.
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
Running `target/debug/loops`
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50
위처럼 index를 기준으로 값이 5가 되는 시점에 반복이 중단된다. 하지만 이런 방식은 에러가 발생하기 쉽다. 정확한 길이의 index를 사용하지 못한다면 프로그램은 오류가 발생할 것이고, 이 방식은 느리다.
이유는 컴파일러가 실행 간에 반복문을 통해 반복될 때마다 요소에 대한 조건 검사를 수행하는 런타임 코드를 추가하기 때문이라고 한다.
이러한 코드일 때 효율적인 대안으로 for
키워드를 사용하는 것이라고 한다.
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("the value is: {}", element);
}
}
위 코드의 결과는 이전에 while
키워드로 작성했던 것과 동일한 결과이다.
for
키워드를 사용한 반복문은 안전하고 간결하기 때문에 가장 보편적으로 사용된다고 한다.
이러한 사용을 위해서 Rust에서 기본 라이브러리로 제공하는 Range
를 사용하게 된다.
Range
는 한 숫자에서 다른 숫자 전까지 모든 숫자를 차례로 생성한다.
예시는 다음과 같다.
fn main() {
for number in (1..4).rev() {
println!("{}!", number);
}
println!("LIFTOFF!!!");
}
위 코드는 range
(1..4) 를 역순하게 하는 rev
메소드를 사용한 카운트다운 프로그램이다.
현재 시리즈는 다음 링크를 공부한 내용을 기록하고 있습니다.
> The Rust Programming Language <