03. 기본 타입 (정수·실수·bool·char·tuple·array)
Rust 의 스칼라 타입(i8/u8/i32/i64/f32/f64/bool/char) 과 복합 타입(tuple/array) 을 한 번에 정리합니다. 다른 언어와 다른 점은 정수 오버플로우 처리, char 가 4바이트 유니코드 스칼라 값이라는 점, 그리고 배열이 컴파일 타임 고정 크기라는 점입니다. Vec(가변 크기 배열) 은 다음 강의에서 다룹니다.
이 강의에서 배우는 것
- 1i32 / u32 / i64 / usize 의 차이와 선택 기준을 안다
- 2f32 와 f64 중 무엇이 기본인지 안다
- 3char 가 1바이트가 아니라 4바이트 유니코드임을 이해한다
- 4tuple 과 array 를 만들고 패턴 매칭·인덱싱으로 분해한다
- 5오버플로우 시 debug / release 빌드의 동작 차이를 안다
소개
Rust 의 기본 타입은 명시적이고 정직합니다. i32 라고 쓰면 32비트 부호 정수가 확실히 보장되고, 플랫폼별 크기에 따라 달라지는 모호한 int 같은 건 없습니다. 다만 한 가지 — usize 만 예외로, **포인터 크기와 같은 부호 없는 정수** 라 인덱스·크기 표현에 씁니다.
핵심 개념
1) 정수 타입 — 길이 × 부호 매트릭스
| 크기 | 부호 있음 | 부호 없음 |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 (기본) | u32 |
| 64-bit | i64 | u64 |
| 128-bit | i128 | u128 |
| arch | isize | usize |
- **i32** 가 기본 추론 타입 — 정수 리터럴은 다 i32
- **usize** 는 인덱스용. `vec[5]` 의 5 는 usize
- **오버플로우** — debug 빌드는 panic, release 빌드는 wrapping (둘 다 안전한 동작이며 UB 아님)
2) 실수 타입
- **f64** 가 기본 (현대 CPU 에서 f32 와 속도 차이 거의 없고 정밀도가 두 배)
- **f32** 는 그래픽·SIMD·임베디드처럼 메모리 절약 필요할 때만
3) bool 과 char
bool 은 true/false. char 는 작은 따옴표로 표기하며 **유니코드 스칼라 값 4바이트** 입니다. `'a'`, `'한'`, `'😀'` 모두 char 한 개.
4) 복합 타입
- **tuple** `(T1, T2, ...)` — 서로 다른 타입을 하나로 묶음
- **array** `[T; N]` — 같은 타입 N 개 고정 크기. 스택에 저장
핵심 예제
타입을 직접 명시한 예:
fn main() {
let a: i32 = -10;
let b: u8 = 255; // u8 의 최댓값
let pi: f64 = 3.141592;
let yes: bool = true;
let k: char = '한';
let smile: char = '😀';
println!("a={}, b={}, pi={}, yes={}, k={}, smile={}", a, b, pi, yes, k, smile);
}tuple 분해와 배열 인덱싱:
fn main() {
let point = (3.0, 4.0); // (f64, f64)
let (x, y) = point; // 패턴으로 분해
println!("x={}, y={}", x, y);
let arr: [i32; 5] = [10, 20, 30, 40, 50];
println!("first={}, last={}", arr[0], arr[4]);
// arr[5] 는 런타임 panic (안전 — UB 아님)
}오버플로우 동작 — debug 와 release 가 다릅니다:
fn main() {
let x: u8 = 255;
let y = x + 1; // debug: panic
// release: 0 (wrapping)
println!("{}", y);
}자주 하는 실수
Q. char 가 1바이트 아닌가요? C 처럼?
A. Rust 의 char 는 **4바이트** 유니코드 스칼라 값입니다. C 의 char 와 다릅니다. UTF-8 인코딩된 바이트는 `u8` 또는 `[u8]` 로 다룹니다 — 다음 강의 시리즈의 String 편에서 자세히.
Q. usize 와 u32 중 인덱스에 뭘 쓰나요?
A. **usize**. 컬렉션의 길이·인덱스는 모두 usize 로 통일돼 있습니다. u32 와 변환은 명시적 `as usize` 필요.
Q. 배열 크기를 런타임에 정하려면?
A. 배열 `[T; N]` 은 안 됩니다. **Vec<T>** 를 쓰세요 — 힙 할당 동적 크기. 다음 다음 강의에서 다룹니다.
정리
- 정수 기본 추론은 i32, 인덱스는 usize, 실수 기본은 f64
- char 는 유니코드 4바이트
- tuple 은 패턴으로 분해, array 는 고정 크기 [T; N]
- 오버플로우는 debug 패닉 / release 래핑 — 둘 다 안전 동작
과제
- i32 최댓값(`i32::MAX`) 을 출력하고, 거기에 1 을 더해 오버플로우 동작을 확인 (debug → panic 메시지 확인)
- 임의의 점 두 개를 tuple 로 만들고 거리(유클리드) 를 구하는 코드 작성
- 이름·나이·키 를 담은 tuple `("홍길동", 30, 180.5)` 를 만들고 분해 출력