Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

형변환

Rust는 기본 타입 간의 암시적 타입 변환(강제)을 제공하지 않습니다. 하지만 as 키워드를 사용하여 명시적 타입 변환(캐스팅)을 수행할 수 있습니다.

정수 타입 간의 변환 규칙은 일반적으로 C 언어의 관례를 따르지만, C에서 정의되지 않은 동작(undefined behavior)이 발생하는 경우는 예외입니다. Rust에서 정수 타입 간의 모든 캐스팅 동작은 잘 정의되어 있습니다.

// 오버플로우가 발생하는 캐스팅으로 인한 모든 에러를 억제합니다.
#![allow(overflowing_literals)]

fn main() {
    let decimal = 65.4321_f32;

    // 에러! 암시적 변환 없음
    let integer: u8 = decimal;
    // FIXME ^ 이 줄을 주석 처리하세요

    // 명시적 변환
    let integer = decimal as u8;
    let character = integer as char;

    // 에러! 변환 규칙에 제한이 있습니다.
    // 부동 소수점은 문자로 직접 변환할 수 없습니다.
    let character = decimal as char;
    // FIXME ^ 이 줄을 주석 처리하세요

    println!("형변환: {} -> {} -> {}", decimal, integer, character);

    // 값을 부호 없는 타입 T로 캐스팅할 때, #![allow(overflowing_literals)]
    // 린트가 위와 같이 지정된 경우에만 값이 새로운 타입에 맞을 때까지
    // T::MAX + 1을 더하거나 뺍니다. 그렇지 않으면 컴파일 에러가 발생합니다.

    // 1000은 이미 u16에 들어맞습니다
    println!("1000을 u16으로 변환하면: {}", 1000 as u16);

    // 1000 - 256 - 256 - 256 = 232
    // 내부적으로는 첫 8개의 최하위 비트(LSB)는 유지되고,
    // 최상위 비트(MSB) 쪽의 나머지 비트들은 잘려 나갑니다.
    println!("1000을 u8로 변환하면 : {}", 1000 as u8);
    // -1 + 256 = 255
    println!("  -1을 u8로 변환하면 : {}", (-1i8) as u8);

    // 양수의 경우, 이는 나머지 연산(modulus)과 동일합니다
    println!("1000 mod 256은 : {}", 1000 % 256);

    // 부호 있는 타입으로 캐스팅할 때, (비트 단위) 결과는 먼저
    // 대응하는 부호 없는 타입으로 캐스팅하는 것과 같습니다. 만약 그 값의
    // 최상위 비트가 1이면, 그 값은 음수입니다.

    // 물론 이미 들어맞는 경우는 제외합니다.
    println!(" 128을 i16으로 변환하면: {}", 128 as i16);

    // 경계 케이스의 경우, 8비트 2의 보수 표현에서 128이라는 값은 -128입니다.
    println!(" 128을 i8로 변환하면 : {}", 128 as i8);

    // 위 예제를 반복합니다
    // 1000을 u8로 변환 -> 232
    println!("1000을 u8로 변환하면 : {}", 1000 as u8);
    // 그리고 8비트 2의 보수 표현에서 232라는 값은 -24입니다.
    println!(" 232를 i8로 변환하면 : {}", 232 as i8);

    // Rust 1.45부터, 부동 소수점을 정수로 캐스팅할 때 `as` 키워드는
    // *포화 캐스팅(saturating cast)*을 수행합니다. 부동 소수점 값이
    // 상한을 초과하거나 하한보다 작으면, 반환되는 값은 해당 경계값이 됩니다.

    // 300.0을 u8로 변환하면 255입니다
    println!(" 300.0을 u8로 변환하면 : {}", 300.0_f32 as u8);
    // -100.0을 u8로 변환하면 0입니다
    println!("-100.0을 u8로 변환하면 : {}", -100.0_f32 as u8);
    // nan을 u8로 변환하면 0입니다
    println!("   nan을 u8로 변환하면 : {}", f32::NAN as u8);

    // 이러한 동작은 약간의 런타임 비용을 발생시키며, unsafe 메서드를 사용하여
    // 피할 수 있습니다. 하지만 결과가 오버플로우되어 **불건전한 값(unsound values)**을
    // 반환할 수 있습니다. 이러한 메서드들은 현명하게 사용하세요:
    unsafe {
        // 300.0을 u8로 변환하면 44입니다
        println!(" 300.0을 u8로 변환하면 : {}", 300.0_f32.to_int_unchecked::<u8>());
        // -100.0을 u8로 변환하면 156입니다
        println!("-100.0을 u8로 변환하면 : {}", (-100.0_f32).to_int_unchecked::<u8>());
        // nan을 u8로 변환하면 0입니다
        println!("   nan을 u8로 변환하면 : {}", f32::NAN.to_int_unchecked::<u8>());
    }
}