100 Exercises To Learn Rust - 2.8 Overflow 풀기

// overflow를 래핑(wrap around)하기 위해 `dev` 프로필을 커스터마이징하세요.
// 올바른 문법을 찾아내기 위해 Cargo의 문서를 확인하세요.
// https://doc.rust-lang.org/cargo/reference/profiles.html
//
// 나중에 설명하겠지만, 커스터마이징은 현재 exercise의 `Cargo.toml`이 아닌 
// 리포지토리 루트의 `Cargo.toml`에 해야 합니다.

pub fn factorial(n: u32) -> u32 {
    let mut result = 1;
    for i in 1..=n {
        result *= i;
    }
    result
}

 

 

test에는 다음과 같은 내용이 추가되었다.

#[test]
    fn twentieth() {
        // 20!은 2432902008176640000으로 u32 타입에 넣기엔 너무 큽니다.
        //기본 dev 프로필로는 `cargo test`를 실행할 시 panic이 일어날 것입니다.
        //우리는 이를 래핑하기를 원합니다.
        assert_eq!(factorial(20), 2_192_834_560);
        //                           ☝️
        // 밑줄(underscore를 사용하면 큰 숫자 리터럴의 가독성을 향상시킬 수 있습니다!
    }

 

 

타입의 최대 크기를 넘어서는 값이 들어오게 되면 오버플로우가 발생하는데, 이를 해결하려면 더 큰 타입으로 자동으로 변환할 수도 있다. 하지만 러스트는 타입 강제 변환에 있어서는 까다로우므로 러스트의 해결책으로 보기는 어렵다.

 

아예 연산을 거부해버리는 방법도 있다. 이는 panic을 통해서 가능하다.

 

혹은 래핑(wrapping, wrap around)하는 방법도 있다. 이는 값을 순환시켜버리는 것이다.

 

예를 들어보자.

u8 타입의 최댓값은 255인데, u8 타입의 1과 u8 타입의 255를 더하면 256으로 최댓값을 초과하게 된다.

이때 256이라는 값을 저장하는 것이 아니라, u8 타입의 최솟값인 0으로 저장한다는 의미이다.

 

부호 있는 타입(i8)이라면 최댓값 127과 1을 더하면 최솟값 -128로 래핑된다.

 

러스트에서 래핑을 사용하려면 프로필 세팅에서 overflow-checks를 false로 설정하면 된다. true로 지정되어 있으면 panic을 발생시킨다.

 

dev 프로필에서는 true가, release 프로필에서는 false가 기본값이다.

 

루트 디렉토리의 cargo.toml의 내용이 다음과 같이 되어 있는데, profile.dev를 직접 설정해서 true로 바꾼다.

# This is needed to guarantee the expected behaviour on that specific exercise,
# regardless of the "global" setting for `overflow-checks` on the `dev` profile.
[profile.dev.package.copy]
overflow-checks = true

 

변경 후

[profile.dev.package.copy]
overflow-checks = true

[profile.dev]
overflow-checks = false