Rust 에서 발산 함수 이해하기

Beginner

This tutorial is from open-source community. Access the source code

소개

이 실습에서는 Rust 에서 !로 표시되는 발산 함수 (diverging function) 에 대해 배웁니다. 발산 함수는 절대로 반환하지 않으며, 반환 타입은 빈 타입입니다. 이는 단 하나의 가능한 값만을 갖는 () 타입과 다릅니다. 발산 함수는 match 분기와 같이 다른 타입으로 캐스팅해야 할 때 유용할 수 있습니다. 또한, 영원히 루프하거나 프로세스를 종료하는 함수의 반환 타입이기도 합니다.

참고: 실습에서 파일 이름을 지정하지 않으면 원하는 파일 이름을 사용할 수 있습니다. 예를 들어 main.rs를 사용하고 rustc main.rs && ./main으로 컴파일 및 실행할 수 있습니다.

발산 함수 (Diverging functions)

발산 함수는 절대로 반환하지 않습니다. !로 표시되며, 이는 빈 타입입니다.

fn foo() -> ! {
    panic!("This call never returns.");
}

다른 모든 타입과 달리, 이 타입은 가능한 값의 집합이 비어 있기 때문에 인스턴스화될 수 없습니다. () 타입과는 다르다는 점에 유의하세요. () 타입은 정확히 하나의 가능한 값을 갖습니다.

예를 들어, 이 함수는 일반적으로 반환하지만 반환 값에는 정보가 없습니다.

fn some_fn() {
    ()
}

fn main() {
    let _a: () = some_fn();
    println!("This function returns and you can see this line.");
}

반면에 이 함수는 호출자에게 제어를 절대로 반환하지 않습니다.

#![feature(never_type)]

fn main() {
    let x: ! = panic!("This call never returns.");
    println!("You will never see this line!");
}

이 개념이 추상적으로 보일 수 있지만 실제로 매우 유용하고 자주 편리합니다. 이 타입의 주요 장점은 다른 모든 타입으로 캐스팅될 수 있기 때문에 match 분기와 같이 정확한 타입이 필요한 곳에서 사용할 수 있다는 것입니다. 이를 통해 다음과 같은 코드를 작성할 수 있습니다.

fn main() {
    fn sum_odd_numbers(up_to: u32) -> u32 {
        let mut acc = 0;
        for i in 0..up_to {
            // 이 match 표현식의 반환 타입은 "addition" 변수의 타입 때문에 u32 여야 합니다.
            let addition: u32 = match i%2 == 1 {
                // "i" 변수는 u32 타입이므로 문제 없습니다.
                true => i,
                // 반면에 "continue" 표현식은 u32 를 반환하지 않지만, 절대로 반환하지 않기 때문에 match 표현식의 타입 요구 사항을 위반하지 않습니다.
                false => continue,
            };
            acc += addition;
        }
        acc
    }
    println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9));
}

또한 네트워크 서버와 같이 영원히 루프하는 함수 (예: loop {}) 또는 프로세스를 종료하는 함수 (예: exit()) 의 반환 타입이기도 합니다.

요약

축하합니다! 발산 함수 실습을 완료했습니다. LabEx 에서 더 많은 실습을 통해 기술을 향상시킬 수 있습니다.