정수는 소수 부분이 없는 수예요. 분수나 소수 부분이 없죠. 기계 안에서는 이진 비트 패턴으로 표현돼요.
정수에는 부호가 있는 것과 없는 것이 있어요. 부호가 있다는 것은, 그 수가 음수인지 아닌지를 나타내기 위해 그 수의 비트 중 하나를 할당한다는 뜻이에요.
모든 정수에는 비트 폭이 있는데, 이는 그 수를 이루는 비트의 개수를 말해요. 이는 그 정수 타입으로 표현할 수 있는 최댓값에 영향을 줘요.
예를 들어, 가장 흔한 정수 타입 중 하나는 u8이에요. 부호가 없는 8비트 정수죠. 이 타입은 1바이트로 익숙하게 느껴질 수도 있어요. 최솟값은 0이고 최댓값은 255예요.
Rust에는 12개의 정수 기본 타입이 있는데, 비트 폭과 부호 유무에 따라 나뉘어요:
| Unsigned | Signed |
|---|---|
u8 |
i8 |
u16 |
i16 |
u32 |
i32 |
u64 |
i64 |
u128 |
i128 |
usize |
isize |
정수의 비트 폭은 항상 u나 i 뒤의 숫자로 나타내요. usize와 isize는 특별해요. 타깃 머신에서 포인터와 같은 폭을 가져요. 즉, 64비트 아키텍처에서는 usize와 isize가 64비트 폭이지만, 32비트 아키텍처에서는 32비트 폭이에요.
일반적으로, 그냥 어떤 수를 표현하고 싶다면 i32를 사용해요. 32비트는 범위가 충분히 넓어서 오버플로가 발생할 가능성이 비교적 적고, 부호 있는 수가 부호 없는 수보다 예상치 못한 점이 적어요. i32는 C의 long이나 Java의 int와 같아요. 숫자 리터럴을 사용하면서 타입을 명시적으로 지정하지 않으면, 기본값은 i32예요.
이진 데이터를 다룬다면, 바이트로 다루는 게 가장 쉬워요: &[u8] 또는 Vec<u8>.
Rust는 컬렉션의 크기와 인덱싱에 usize를 사용해요. 이론적으로 컴퓨터는 usize::MAX 바이트의 메모리까지만 주소를 지정할 수 있기 때문에, 그보다 큰 메모리 내 컬렉션은 불가능해요. 따라서 컬렉션을 많이 다룬다면 usize가 유용할 수 있어요.
데이터가 32비트 정수에 들어가지 않는다면, 64비트나 128비트 정수로 넓히는 것을 고려해 봐요. 데이터가 128비트 정수에도 들어가지 않는다면, num-bigint에서 제공하는 것과 같은 큰 정수 타입을 사용할 수 있어요.
16비트 정수는 그다지 흔하지 않지만, 특정 마이크로컨트롤러를 대상으로 할 때 유용할 수 있어요.
애플리케이션에 유효한 음수 경우가 없다는 것을 안다면, 부호 있는 정수 대신 부호 없는 정수를 사용하는 게 좋아요. 개수를 세는 것이 좋은 예예요.
Rust에는 암시적 숫자 변환이 없어요. 정수 타입 사이를 캐스팅해야 한다면, 두 가지 기본 전략이 있어요: as 키워드, 그리고 From과 TryFrom 트레이트예요.
as 키워드를 사용하는 것은 간단해요: expr as Type. 하지만 as 캐스트를 사용할 때 명심해야 할 주의할 점과 미묘한 부분이 여러 가지 있어요.
트레이트 기반 캐스팅은 조금 더 복잡하지만, 더 안전해요: 변환 트레이트는 안전한 경우에만 구현돼요. 예를 들어, i32는 From<u8>, From<u16>, From<i8>, From<i16>을 구현해요: 이 타입들로 표현할 수 있는 어떤 값이든 i32로 표현할 수 있다는 것이 보장돼요. i32::from(expr) 또는 expr.into()처럼 사용할 수 있는데, 여기서 expr은 그 타입 중 하나로 결정돼요. i32는 TryFrom<u32>, TryFrom<u64>, TryFrom<u128>, TryFrom<usize>, TryFrom<i64>, TryFrom<i128>, TryFrom<isize>도 구현해요. 이러한 변환은 값에 따라 명시적으로 성공하거나 오버플로해요. 이것들을 사용하려면 std::convert::TryFrom 또는 std::convert::TryInto 트레이트를 적절히 임포트한 다음, i32::try_from(expr) 또는 expr.try_into()를 사용해야 하는데, 여기서 expr은 적절한 타입으로 결정돼요.
as 캐스팅 대신 트레이트 기반 캐스팅을 사용하는 것이 일반적으로 선호돼요. 특히 더 넓은 타입에서 더 좁은 타입으로 변환할 때 그렇죠. 트레이트 기반 캐스팅은 as 캐스팅보다 무시할 수 있을 만큼만 비용이 더 들어요: 성능 때문에 as를 사용하는 것은 극도로 자주 실행되는 루프가 아니라면 그럴 가치가 없어요.