소개
이 실습에서는 Rust 에서 캐스팅에 대해 배우고 as 키워드를 사용하여 명시적인 형 변환을 수행하는 방법을 배웁니다.
참고: 실습에서 파일 이름을 지정하지 않으면 원하는 파일 이름을 사용할 수 있습니다. 예를 들어
main.rs를 사용하고rustc main.rs && ./main으로 컴파일 및 실행할 수 있습니다.
이 실습에서는 Rust 에서 캐스팅에 대해 배우고 as 키워드를 사용하여 명시적인 형 변환을 수행하는 방법을 배웁니다.
참고: 실습에서 파일 이름을 지정하지 않으면 원하는 파일 이름을 사용할 수 있습니다. 예를 들어
main.rs를 사용하고rustc main.rs && ./main으로 컴파일 및 실행할 수 있습니다.
Rust 는 기본형 타입 간의 암시적 형 변환 (강제 변환) 을 제공하지 않습니다. 하지만 명시적인 형 변환 (캐스팅) 은 as 키워드를 사용하여 수행할 수 있습니다.
정수형 타입 간의 변환 규칙은 일반적으로 C 규칙을 따르지만, C 에서 정의되지 않은 동작이 발생하는 경우는 제외합니다. 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;
// 오류! 변환 규칙에 제한이 있습니다.
// 부동소수점 수는 char 로 직접 변환될 수 없습니다.
let character = decimal as char;
// FIXME ^ 이 줄을 주석 처리하세요
println!("캐스팅: {} -> {} -> {}", decimal, integer, character);
// 부호 없는 타입 T 로 값을 캐스팅할 때,
// 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);
// 양수의 경우, 이는 모듈러 연산과 같습니다.
println!("1000 을 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);
// 232 의 값을 8 비트 2 의 보수 표현으로 나타내면 -24 입니다.
println!("232 를 i8 로 캐스팅한 결과는: {}", 232 as i8);
// Rust 1.45 부터 `as` 키워드는 부동소수점에서 정수로 캐스팅할 때 *포화 캐스팅*을 수행합니다. 부동소수점 값이 상한을 초과하거나 하한보다 작으면, 반환 값은 초과된 경계 값과 같습니다.
// 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 메서드를 사용하여 피할 수 있습니다. 그러나 결과가 오버플로우될 수 있으며 **부정확한 값**을 반환할 수 있습니다. 이러한 메서드를 신중하게 사용하십시오.
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>());
}
}
축하합니다! 캐스팅 실습을 완료했습니다. LabEx 에서 더 많은 실습을 통해 기술을 향상시킬 수 있습니다.