비욘드 JS: 러스트 - Function & Control Flow

dante Yoon·2022년 12월 18일
0

beyond js

목록 보기
4/20
post-thumbnail

동영상 강의로 보기

글을 시작하며

안녕하세요, 단테입니다.
오늘은 러스트의 함수와 조건문에 대해 알아보겠습니다.

함수

러스트에서 함수 작성 및 호출은 타입스크립트의 함수와 굉장히 유사합니다.

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입니다.

Statements and Expressions

러스트에서 statement와 expression을 구분하는 것은 매우 중요합니다.

러스트에서 statement란 값을 반환하지 않고 특정 역할만 수행하는 코드를 의미하고 expression은 값을 반환합니다. 함수에서 특정 값을 반환하기 위해서는 statement가 아닌 expression을 작성해야 하며 변수 선언에 사용할 수 있습니다.

두 단어를 구분하지 않고 expression이 필요한 곳에 statement를 작성한다면 러스트 컴파일러가 컴파일 에러를 발생시키기 때문에 효율적이고 정확한 러스트 코드를 작성하기 위해서는 두 가지를 확실히 이해해야 합니다.

statements

다음의 코드에서 각기 다른 역할을 하는 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);
    }
}

pattern binding ;

let x = 5에서 let xpattern binding이라고 하며 statement 입니다.

println!

콘솔 출력을 위해 println! 함수의 호출을 했습니다. 호출하는 함수가 값을 반환하지 않는다면 statement입니다.

loop

러스트에서 loop문을 사용한 반복문은 특정 코드 블럭을 반복해서 실행하기 위해 사용하며 statement입니다.

fn main() {
    let mut count = 0;
    loop {
        count += 1;
        if count > 5 {
            break;
        }
        println!("{}", count);
    }
}

Expressions

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();
}

assignment

let x = 5 에서 = 5는 pattern binding에 assignment를 하는 부분입니다. assignment= 5는 expression입니다.

arithmetic operation

pattern binding let y에 x + 10을 assignment 하고 있습니다. x + 10은 arithmetic operation이며 expression입니다.

add(x,y)

함수 호출 시 값을 반환한다면 statement가 아니라 expression입니다.

조건문

러스트에서 if 문을 사용해 조건문을 표기할 시 {} 내부에서 값을 반환할 시 해당 조건문은 expression이며 pattern binding에 사용할 수 있습니다.

조건문은 항상 expression인 것은 아닙니다.

loops

앞서 statement 종류에서 봤었던 loop statement말고 다른 반복문을 사용해 expression을 작성할 수 있습니다. 연속된 값들을 for 문이나 iterators를 통해 생성할 수 있습니다.

let numbers: Vec<i32> = (0..10).collect();

페턴 바인딩에 0부터 9까지의 값을 반복해 numbers 변수에 바인딩 시켰습니다. 이러한 반복문은 expression입니다.

Control flow

러스트에서는 statement나 expression의 실행 순서를 조절할 수 있는 몇 가지의 control flow를 제공합니다.

if, for, while, match가 그런 것들 입니다.

if expression

다음의 코드에서 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

다음 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

다음의 코드에서 첫번째 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 block

다음의 loop 블럭은 break가 명시적으로 실행될 때까지 계속 블럭 내부를 반복해서 실행합니다.

fn main() {
    let mut count = 0;
    loop {
        count += 1;
        println!("{}", count);
        if count > 5 {
            break;
        }
    }
}

loop & if

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 block expression

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

중첩 형태의 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

러스트에서 while 문을 통해 특정 조건을 만족할 때까지 계속 동작을 반복할 수 있습니다.

fn main() {
    let mut count = 0;
    while count < 5 {
        count += 1;
        println!("{}", count);
    }
}

러스트에서 while loop는 값을 반환할 수 없기 때문에 statement입니다.

글을 마무리하며

오늘은 프로그래밍에 있으면 모든 것을 할 수 있으나 없으면 아무것도 못하는 조건문과 control flow, 함수에 대해 알아보았습니다.

수고 많으셨습니다.
감사합니다 :)

profile
성장을 향한 작은 몸부림의 흔적들

0개의 댓글