[Rust] 러스트 자료형(데이터 타입)

Data Type

type detail example
i8, i16, i32, i64, i128, u8, u16, u32, u64, u128 i 해당 비트 크기를 갖는 부호 있는 정수
u 해당 비트 크기를 갖는 부호 없는 정수
50, -5i8, 0x100u16, 0o100i16, 20_933_684u64, b'a' (u8 바이트 리터럴)
isize, usize 머신 주소 크기(32 또는 64비트) 164, -0b0011_1010isize
f32, f64 IEEE754 단정밀도, 배정밀도 부동소수점 1.1684, 3.14f32, 6.0221e23f64
bool true, false
char 32비트 크기를 갖는 유니코드 문자 'b', '\n', '\7f', '\u{CA1}', '準'
(char, u8, i32) 혼합 가능한 튜플 ('%', 0x7f, -1)
() 유닛(빈 튜블) ()
struct S {x: f32, y: f32} 이름 있는 필드로 된 구조체 S { x:119.0, y: 200.0 }
struct T (i32, char); 튜플형 구조체 T(100, 'X')
struct E; 필드를 갖지 않는 유닛형 구조체 E
enum Attend { OnTime, Late(u32) } 열거, 대수적 데이터 타입 Attend::Late(5), Attend::OnTime
Box<Attend> 박스: 힙에 있는 값의 소유권을 갖는 포인터 Box::new(Late(15))
&i32, &mut i32 공유된 레퍼런스와 변경할 수 있는 레퍼런스, 참조 대상보다 더 오래 지속될 수 없는 소유권을 갖지 않는 포인터 &s.y, &mut v
String 동적 크기를 갖는 문자열 "배고파".to_string()
&str str 레퍼런스: 소유권을 갖지 않는 텍스트 포인터 "필승정예공군".&s[0..2]
[f64; 4], [u8; 256] 요소의 타입이 모두 같은 고정 길이 배열 [1.0, 0.0, 0.0, 1.0], [b' '; 256]
Vec<f64> 요소의 타입이 모두 같은 가변 길이 벡터 vec![0.123, 0.456, 0.789]
&[u8], &mut [u8] 슬라이스 레퍼런스: 배열이나 벡터의 일부분을 참조하는 레퍼런스 &v[10..20], &mut a[..]
Option<&str> 옵션값: None(없음), Some(v) (있음, 값은 v) Some("Ph."), None
Result<u64, Error> 실패할 수도 있는 작업 결과 : 성공값 Ok(v), 오류값 Err(e) Ok(4096), Err(Error::last_os_error())
&dyn Any, &mut dyn Read 트레이드 객체: 주어진 메서드 집합을 구현하고 임의의 값을 참조하는 레퍼런스 value as &dyn Any, &mut file as &mut dyn Read 
fn(&str) -> bool 함수 포인터 str::is_empty
클로저 타입은 기록 혀앹를 갖지 않는다 클로저 |a, b| { a*a | b*b }

 


정수형 오버플로우 처리

정수형 자료형의 주의점 (release시 충분히 정수 오버플로우가 발생할 수 있다.)
디버그 모드에서 정수 오버플로우가 발생하면 panic을 발생시키는 검사를 포함하지만, release 모드로 컴파일 할 경우 검사가 실행파일에 포함되지 않음. two's complement wrapping을 통해 wrap around를 거친다.

 

표준 라이브러리에서 아래 메서드를 사용 할 수 있다.

  • wrapping_add와 같은 wrapping_* 메서드로 감싸기 동작 실행하기
    // 첫 번째 곱은 u16로 표현 가능
    // 두 번째 곱은 그럴 수 없으므로 250000을 2^16로 나눈 나머지 산출
    assert_eq!(100_u16.wrapping_mul(200), 20000);
    assert_eq!(500_u16.wrapping_mul(500), 53392);
    
    // 부호있는 타입을 대상으로 하는 연산은 음숫값으로 순환되기도 함
    assert_eq!(500_i16.wrapping_mul(500), -12144);
    
    // 쉬프트는 이동거리가 값이 크기 안에 들어가도록 순환
    // 16비트 타입일 때 17비트 쉬프트는 1비트 쉬프트와 같은 역할
    assert_eq!(5_i16.wrapping_shl(17), 10);
  • checked_* 메서드를 사용하여 오버플로우가 발생하면 None 값 반환하기
    // 10과 20의 합은 u8로 표현할 수 있다.
    assert_eq!(10_u8.checked_add(20), Some(30));
    
    // 하지만 100과 200의 합은 그럴 수 없다.
    assert_eq!(100_u8.checked_add(200), None);
    
    // 덧셈을 하는데 오버플로우가 발생하면 패닉에 빠진다.
    let sum = x.checked_add(y).unwrap();
    
    // 이상하지만 부호 있는 나눗셈도 오버플로우를 일으킬 수 있다.
    // 부호 있는 n비튼는 -2^n-1은 표현하지만 2^n-1은 표현 할 수 없다.
    assert_eq!((-128_i8.checked_div(-1), None);
  • overflowing_* 메서드를 사용하여 값과 함께 오버플로우 발생이 있었는지를 알려주는 부울린 값 반환하기
    // overflowing은 (result, overflowed) 튜플 반환, result는 반환 값, overflowed는 발생 여부 bool
    assert_eq!(255_u8.overflowing_sub(2), (253, false));
    assert_eq!(255_u8.overflowing_add(2), (1, true));
    assert_eq!(5_u16.overflowing_shl(17), (10, true));
  • saturating_* 메서드를 사용하여 값의 최대 혹은 최솟값 사이로 제한하기
    // 표현할 수 있는 값 중 수학적으로 옳은 결과에 가장 가까운 값을 반환
    assert_eq!(32760_i16.staurating_add(10), 32767);
    assert_eq!((-32760_i16).saturating_sub(10), -32768);

checked_*, wrapping_*, saturating_*, overflowing_* 뒤에 붙은 * 접미사엔 연산을 넣는다.

접미사 예시
add 100_i8.checked_add(27) == Some(127)
sub 10_u8.checked_sub(11) == None
mul 128_u8.saturaing_mul(3) == 255
div 64_u16.wrapping_div(8) == 8
rem (-32768_i16).wrapping_rem(-1) == 0
neg (-128_i8).checked_neg() == None
abs (-32768_i16).wrapping_abs() == -32768
pow 3_u8.checked_pow(4) == Some(81)
shl 10_u32.wrapping_shl(34) == 40
shr 40_u64.wrapping_shr(66) == 10

 


대리 표기법으로만 사용 가능한 문자들

문자 바이트 리터럴 수칫값
' (작은 따음표) b'\'' 39u8
\ (백슬래시) b'\\' 92u8
새 줄 b'\n' 10u8
캐리지 리턴 b'\r' 13u8
b'\t' 9u8

 

 

 


ref. https://rinthel.github.io/rust-lang-book-ko/ch03-02-data-types.html