본문 바로가기

Rust/Basic

[Rust Tutorial] 6 - Control Flow

 

 


Intro

rust의 흐름 제어(분기문, 반복문)에 대한 설명과 예제입니다. rust는 이 부분에서는 타 언어들과 거의 비슷합니다. 차이가 있다고 한다면 다음과 같은 부분이 있습니다.

 

  1. 무한루프 예제인 loop
  2. slice 표기법 (1..5, 1..=10)
  3. match(switch, case), if let

 

코드 예제를 통해 확인해 보겠습니다.


 

Code Example

Rust 1.79.0 (released 2024-06-13) 

fn main(){
    // =========================================
    // Conditionals (분기문)
    // =========================================

    /* [Example] if, else : 가장 기초적인 분기문 */
    let number = 5;

    if number > 0 {
        println!("Positive number");
    } else if number == 0{
        println!("Zero");
    } else {
        println!("Negative number");
    }

    
    /* [Example] match : (switch case같은 동작) */    
    // match에서 <pattern>에 속하는지를 검사함.
    // pattern에 올 수 있는 값들은 아래와 같음
    fn match_number(number:i32) {
        match number {
            1 => println!("One"),                   // literal
            2..5 => println!("Two, Three, Four"),   // Range type도 사용할 수 있다.
            5..=10 => println!("5 ~ 10"),           // Range Type을 끝 숫자를 포함시킬 수도 있다.
            _ => println!("no match"),              // Default
        }
    }
    match_number(number);

    // compound Type의 match 활용
    let tuple = (2, 4);
    fn match_tuple(tuple: (i32, i32)){
        match tuple {
            // 값을 빼서 가져올 수 있다.
            (1, y) => println!("tuple. first value is 1, second value is {y}"),
            (2, y) => println!("tuple. first value is 2, second value is {y}"),
            (x, 10) => println!("tuple. first value is {x}, second value is 10"),
            _ => println!("no match"),
        }
    }
    match_tuple(tuple);

    // Custom Type의 match 활용 (Option, Result같은 차후 나올 Type에서 자주 활용)
    enum Animal {
        Dog(String),
        Cat(String),
        Bird(String),
    }
    let dog = Animal::Dog(String::from("bull"));
    let cat = Animal::Cat(String::from("kitty"));
    let bird = Animal::Bird(String::from("eagle"));
    fn match_animal(animal: Animal){
        match animal {
            Animal::Bird(name) => println!("A bird named {}", name),
            Animal::Cat(name) => println!("A cat named {}", name),
            Animal::Dog(name) => println!("A dog named {}", name),
        }
    }

    match_animal(dog);
    match_animal(cat);
    match_animal(bird);

    /* [Example] if let */
    // if let은 match에서 한 가지 match case에 대해 다루고 싶을 때 사용
    // if (let <pattern> => <target>) {match true condition} else {match false condition}

    // literal 예제 (match와 비슷하다는 것을 보여주는 예제일뿐, 이렇게는 사실 잘 사용 안함)
    let number = 10;
    if let 1..=10 = number  {           // number가 1..=10에 match되는가?
        println!("number is in 1 ~ 10");
    } else if let 11..=20 = number {    // number가 11..=20에 match되는가?
        println!("number is in 11 ~ 20");
    } else {
        println!("number is not in 1 ~ 20");
    }

    // enum을 활용한 if let example
    // 차후에 Option Type 처리, Result Type을 활용한 Error handling에서 많이 사용된다.
    #[allow(warnings)]
    enum Status{
        Success(String),
        Fail(String),
    }

    let success_status = Status::Success(String::from("get message success"));
    let fail_status = Status::Fail(String::from("get message failed"));

    fn get_fail_status_message(status:Status){
        if let Status::Fail(message) = status {
            println!("status : success. message : {message}");
        } // fail message인 경우 message 출력 함수
    }

    get_fail_status_message(success_status);    // 아무 메세지를 출력하지 않음
    get_fail_status_message(fail_status);       // fail message 출력

    
    // =========================================
    // Loops (반복문)
    // =========================================
    
    /* for : 전통적인 방식 */
    for i in 0..4{
        println!("i : {i}");    // 0, 1, 2, 3
    }

    for i in 0..=4{        // 끝자리수를 포함하고 싶을 때
        println!("i : {i}");    // 0, 1, 2, 3, 4
    }

    // array
    let arr = [1, 2, 3, 4, 5];
    // 배열 같은 type은 iter() method를 활용해 각 원소의 주소값을 받아올 수 있다.
    for &item in arr.iter(){            // &item으로 선언해서 item을 값으로 받을 수 있다.
        println!("arr item : {item}");
    }

    // ref를 사용하지 않는다면 어떻게 될까?
    // println!은 &i32, i32를 둘 다 값으로 출력할 수 있다. 그래서 error를 출력하지 않는다.
    // 하지만 pointer에 대한 개념이 잘 잡혀있지 않다면 이런 습관은 문제가 될 수 있다.
    // println!에 value를 출력할 수 있도록 type을 지켜주도록 습관을 들이자
    for item in arr.iter(){             // for item in arr.iter()로 하면 &i32가 출력된다.
        println!("arr *item : {}", *item);    
        println!("arr item : {}", item);      // println!은 &i32, i32를 둘 다 값으로 출력할 수 있다.
    }

    // enumerate : item의 index를 tuple로 묶어서 출력 (0, 1, 2, 3...)
    let v = vec![10, 20, 30, 40];
    for (index, &item) in v.iter().enumerate(){
        println!("vector item {index} : {item}");
    }

    // zip : 2개의 iterator를 묶어서 출력
    // 서로의 길이가 차이난다면 짧은쪽에 맞춰져서 출력됨
    for (&arr_item, &vec_item) in arr.iter().zip(v.iter()) {
        println!("arr item : {arr_item}, vec item : {vec_item}");   // (1, 2, 3, 4), (10, 20, 30, 40)
    }

    // mutable
    let mut v_mut = vec![1, 2, 3];
    let mut a_mut = [4, 5, 6];

    // mutable한 ref를 받아온다.
    for (v_item_ref, a_item_ref) in v_mut.iter_mut().zip(a_mut.iter_mut()){
        *a_item_ref *= 10;  // a_item_ref의 값을 control할 수 있도록 deref(*)한 후 값을 변경
        *v_item_ref += 10;  // a_item_ref의 값을 control할 수 있도록 deref(*)한 후 값을 변경
    }
    println!("{v_mut:?}, {a_mut:?}");   // [11, 12, 13], [40, 50, 60]


    /* while: 조건이 false가 될때까지 반복. continue나 break keyword도 활용할 수 있다. */
    let mut counter = 0;

    while counter < 5 { // 5미만일때는 반복
        println!("while counter : {counter}");
        counter += 1;

        if counter <= 3 {    // counter가 3 미만이면
            continue;       // 반복문 처음으로 되돌림. 밑의 counter를 돌지 않음
        }

        println!("counter is over 3");
    }


    /* loop: 무한 루프 (while true같은 개념) */
    let mut counter = 0;

    loop {
        if counter > 5 {
            break;          // loop는 break만으로 빠져나올 수 있다.
        }
        println!("loop counter : {counter}");
        counter += 1;
    }
}

 

 


 

* reference

 - https://doc.rust-lang.org/book/

'Rust > Basic' 카테고리의 다른 글

[Rust Tutorial] 8 - Struct, Impl, Trait  (0) 2024.11.18
[Rust Tutorial] 7 - Ownership  (0) 2024.11.17
[Rust Tutorial] 5 - Function  (0) 2024.11.17
[Rust Tutorial] 4 - Data Type  (0) 2024.11.14
[Rust Tutorial] 3 - Variables  (0) 2024.11.14