안녕하세요, 단테입니다.
오늘은 러스트의 함수와 조건문에 대해 알아보겠습니다.
러스트에서 함수 작성 및 호출은 타입스크립트의 함수와 굉장히 유사합니다.
fn main() {
// define the function
fn say_hello() {
println!("Hello, world!");
}
// call the function
say_hello();
}
함수 작성 시 리턴 타입은 다음과 같이 ->
표기를 통해 작성합니다.
fn main() {
// define the function
fn add(x: i32, y: i32) -> i32 {
x + y
}
// call the function and print the result
let result = add(2, 3);
println!("The result is: {}", result);
}
위의 함수 add는 x,y 파라메터는 각각 i32
타입, 리턴 타입은 i32
입니다.
러스트에서 statement와 expression을 구분하는 것은 매우 중요합니다.
러스트에서 statement란 값을 반환하지 않고 특정 역할만 수행하는 코드를 의미하고 expression은 값을 반환합니다. 함수에서 특정 값을 반환하기 위해서는 statement가 아닌 expression을 작성해야 하며 변수 선언에 사용할 수 있습니다.
두 단어를 구분하지 않고 expression이 필요한 곳에 statement를 작성한다면 러스트 컴파일러가 컴파일 에러를 발생시키기 때문에 효율적이고 정확한 러스트 코드를 작성하기 위해서는 두 가지를 확실히 이해해야 합니다.
다음의 코드에서 각기 다른 역할을 하는 statement를 확인해보겠습니다.
fn main() {
// variable declaration is a statement
let x = 5;
// function call is a statement
println!("The value of x is: {}", x);
// loop is a statement
for i in 0..5 {
println!("{}", i);
}
}
let x = 5
에서 let x
는 pattern binding
이라고 하며 statement 입니다.
콘솔 출력을 위해 println! 함수의 호출을 했습니다. 호출하는 함수가 값을 반환하지 않는다면 statement입니다.
러스트에서 loop문을 사용한 반복문은 특정 코드 블럭을 반복해서 실행하기 위해 사용하며 statement입니다.
fn main() {
let mut count = 0;
loop {
count += 1;
if count > 5 {
break;
}
println!("{}", count);
}
}
expression에 대한 예시를 살펴보겠습니다.
fn main() {
// literal values are expressions
let x = 5;
// arithmetic operations are expressions
let y = x + 10;
// function calls can be expressions if they return a value
let z = add(x, y);
// if statements are expressions
let a = if x > y { x } else { y };
// loops
let numbers: Vec<i32> = (0..10).collect();
}
let x = 5
에서 = 5
는 pattern binding에 assignment
를 하는 부분입니다. assignment
인 = 5
는 expression입니다.
pattern binding let y
에 x + 10을 assignment 하고 있습니다. x + 10은 arithmetic operation이며 expression입니다.
함수 호출 시 값을 반환한다면 statement가 아니라 expression입니다.
러스트에서 if 문을 사용해 조건문을 표기할 시 {}
내부에서 값을 반환할 시 해당 조건문은 expression이며 pattern binding에 사용할 수 있습니다.
조건문은 항상 expression인 것은 아닙니다.
앞서 statement 종류에서 봤었던 loop statement말고 다른 반복문을 사용해 expression을 작성할 수 있습니다. 연속된 값들을 for
문이나 iterators
를 통해 생성할 수 있습니다.
let numbers: Vec<i32> = (0..10).collect();
페턴 바인딩에 0부터 9까지의 값을 반복해 numbers 변수에 바인딩 시켰습니다. 이러한 반복문은 expression입니다.
러스트에서는 statement나 expression의 실행 순서를 조절할 수 있는 몇 가지의 control flow를 제공합니다.
if
, for
, while
, match
가 그런 것들 입니다.
다음의 코드에서 if문은 pattern binding에 사용하고 있으며 이 경우 if문은 expression입니다.
중요한 점은
if문이 expression이 되려면 항상
else
문이 있어야 한다는 점입니다. 모든 조건에서 특정 값을 반환해야 하고 동일한 타입의 값을 반환해야 합니다.
Copy code
fn main() {
let x = 5;
let y = 10;
// if expression
let result = if x > y { x } else { y };
println!("The bigger number is: {}", result);
}
다음 if 문은 값을 반환하지 않습니다. 따라서 statement 입니다.
fn main() {
let x = 5;
let y = 10;
// if statement
if x > y {
println!("x is bigger than y");
} else {
println!("y is bigger than x");
}
}
다음의 코드에서 첫번째 for loop는 0 부터 4까지의 범위의 변수 i의 값을 출력하고 있습니다.
두번째 for loop는 names
라고 하는 string 벡터 값들을 순회하고 있습니다.
fn main() {
// iterate over a range of numbers
for i in 0..5 {
println!("{}", i);
}
// iterate over a vector of strings
let names = vec!["Alice", "Bob", "Charlie"];
for name in names {
println!("{}", name);
}
let numbers: Vec<i32> = (0..10).collect();
println!("The numbers are: {:?}", numbers);
// perform a calculation using a for loop
let sum = (0..5).fold(0, |acc, x| acc + x);
println!("The sum is: {}", sum);
}
위 코드에서 세번째와 네번째의 for loop는 collect method와 fold method를 사용해 범위 내의 숫자들을 사용해 계산을 수행합니다. 3,4번째의 for loop는 expression입니다.
다음의 loop
블럭은 break가 명시적으로 실행될 때까지 계속 블럭 내부를 반복해서 실행합니다.
fn main() {
let mut count = 0;
loop {
count += 1;
println!("{}", count);
if count > 5 {
break;
}
}
}
loop 블럭은 흔히 if 나 match와 더불어 사용하기도 합니다.
다음의 예제에서는 count가 짝수이거나 홀수일때 다른 글자를 콘솔에 출력합니다. 그리고 숫자가 5를 초과한다면 루프 블럭을 탈출합니다.
fn main() {
let mut count = 0;
loop {
count += 1;
if count % 2 == 0 {
println!("{} is even", count);
} else {
println!("{} is odd", count);
}
if count > 5 {
break;
}
}
}
loop 블럭에서 break문을 사용할 때 값을 반환한다면 다음과 같이 expression으로 작성할 수 있습니다.
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}
중첩 형태의 loop 블럭에서 break문을 어떻게 사용함에 따라 어떤 루프 블럭을 탈출할 것인지 명시적으로 지정할 수 있습니다. 다음을 확인해봅시다.
다음 코드에서 첫번째 루프에 counting_up
이라는 loop label
을 통해 중첩 루프 블럭에서 최외각 루프 블럭인 counting_up
을 바로 탈출할 수 있는 것을 볼 수 있습니다.
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}");
}
러스트에서 while 문을 통해 특정 조건을 만족할 때까지 계속 동작을 반복할 수 있습니다.
fn main() {
let mut count = 0;
while count < 5 {
count += 1;
println!("{}", count);
}
}
러스트에서 while loop는 값을 반환할 수 없기 때문에 statement
입니다.
오늘은 프로그래밍에 있으면 모든 것을 할 수 있으나 없으면 아무것도 못하는 조건문과 control flow, 함수에 대해 알아보았습니다.
수고 많으셨습니다.
감사합니다 :)