# 데이터 타입

러스트에서는 모든 값이 특정한 데이터 타입에 속하며, 이러한 타입들은 컴파일 시점에 엄격하게 확인된다. 이는 프로그램의 안전성과 성능에 밀접하게 관련되어 있다. 러스트의 데이터 타입은 크게 스칼라 타입과 컴파운드 타입으로 나뉘며, 이외에도 문자열 슬라이스나 참조처럼 메모리 관리와 깊게 관련된 타입들이 존재한다. 러스트는 정적 타입 언어이지만 타입 추론 기능을 제공하여, 많은 경우 개발자가 타입을 명시하지 않아도 컴파일러가 자동으로 타입을 결정한다.

스칼라 타입의 가장 대표적인 예는 정수와 부동소수점 타입이다. 정수형으로는 부호가 있는 i8, i16, i32, i64, i128, isize와 부호가 없는 u8, u16, u32, u64, u128, usize가 있으며, 각각 차지하는 비트 수와 저장할 수 있는 값의 범위가 다르다. 예를 들어 i32는 -2,147,483,648부터 2,147,483,647 범위의 값을 표현할 수 있고, isize나 usize는 시스템 아키텍처에 따라 32비트 또는 64비트 정수의 크기를 갖는다. 특별히 let 키워드만 사용하여 변수를 선언하고 초기화하는 경우, 정수는 i32로 추론되는 경향이 있다. 부동소수점 타입으로는 f32와 f64가 있는데, 디폴트로는 f64가 사용될 만큼 충분한 정밀도와 넓은 범위를 제공한다. 큰 수를 코드에서 표현할 때에는 가독성을 위해 밑줄을 사용할 수 있다.

정수 오버플로우 문제를 유의해야 한다. 예를 들어 u8 타입은 최대 255의 값까지 저장 가능하므로 그 이상의 값을 대입하면 오버플로우가 발생할 수 있다. 디버그 모드에서는 이 문제를 즉시 감지해 런타임 에러로 이어지지만, 릴리스 모드에서는 오버플로우 시 wrapping 같은 행위가 일어나므로 주의해야 한다.

불리언 타입은 bool 키워드를 사용하며 true 또는 false 두 가지 값 중 하나만을 갖는다. 조건문과 같은 제어 구조에서 자주 사용되며, 메모리 공간은 1바이트로 처리된다. 다른 언어와 달리 정수값을 통해 참/거짓을 표현하지 않고, 반드시 bool 타입을 사용해야 한다.

문자 타입은 char 키워드를 사용하며, 실제 내부 표현은 4바이트(유니코드 스칼라 값)다. 따라서 영문 알파벳뿐 아니라 한글, 이모지 같은 다양한 문자를 동일하게 다룰 수 있다. 예를 들어 let c: char = '가'; 와 같은 방식으로 한글 문자를 직접 변수에 할당할 수 있다.

컴파운드 타입에는 여러 개의 값을 하나로 묶는 튜플과 배열이 있다. 튜플은 서로 다른 타입들을 묶어 하나의 논리적 단위로 표현할 수 있으며, 소괄호로 묶어 선언한다. 튜플에 접근할 때는 인덱스를 사용한다. 예를 들어 다음 코드는 튜플의 사용 예시다.

```rust
fn main() {
    let person = ("Alice", 30, true);
    let name = person.0;
    let age = person.1;
    let is_active = person.2;
    println!("이름: {}, 나이: {}, 활성 상태: {}", name, age, is_active);
}
```

배열은 고정된 길이와 동일한 타입의 원소들을 가진다. 대괄호를 사용해 선언하고, 인덱스는 0부터 시작한다. 예를 들어 let nums = \[1, 2, 3, 4, 5]; 와 같이 선언할 수 있다. 튜플과 달리 길이가 고정되어 있으므로, 런타임에 사이즈를 변경할 수 없다. 배열의 슬라이스(slice)는 배열의 일부분을 참조하며, \&nums\[1..3]처럼 범위를 지정하여 참조한다. 슬라이스는 원본 데이터를 복사하지 않고 참조만 유지하므로, 메모리를 절약하며 일부 구간을 안전하게 다룰 수 있게 해준다.

문자열 슬라이스 \&str는 UTF-8로 인코딩된 문자열을 가리키는 참조 타입이다. 예를 들어 &"Hello" 같은 형태로 작성되며, 스트링 리터럴의 주소를 가리키거나 이미 존재하는 문자열의 일부 구간을 슬라이스로 받아올 수 있다. 소유권을 갖는 String 타입과 구분되며, String은 힙 영역에 할당되고 문자열 조작 시 동적으로 크기를 바꿀 수 있는 반면, \&str는 고정된 크기를 갖는 불변의 참조다.

타입 표기는 변수 선언 시 명시적으로 할 수도 있고, 러스트 컴파일러가 타입을 추론하도록 맡길 수도 있다. 정수나 실수 리터럴을 사용할 때는 추론이 가능하지만, 모호성이 있는 경우 개발자가 직접 : i32 혹은 : f64 같은 타입 어노테이션을 작성해야 한다. 예를 들어 let x: i32 = 42; 와 같이 변수 선언 시에 타입을 명시적으로 첨언할 수 있다. 반대로 let y = 42; 와 같이 작성하면 러스트는 y를 i32 타입으로 추론한다.

러스트에서 참조 타입 \&T는 T 타입의 메모리를 직접 소유하지 않고, 단지 대여(borrow)하는 형태를 의미한다. 소유권을 명확히 하여 메모리 안전성을 보장하는 러스트의 특성상, 참조를 생성하거나 사용하기 위해서는 스코프, 라이프타임, 가변성 등에 관한 규칙을 따라야 한다. 예를 들어 \&mut T는 T에 대한 가변 참조를 의미하며, 가변 참조는 스코프 내에서 동시에 하나만 존재할 수 있다.

데이터 타입은 러스트에서 중요한 개념이며, 정확히 이해해야 컴파일 에러나 예상치 못한 동작을 피할 수 있다. 정적 타입 언어로서 러스트가 제공하는 엄격한 타입 검사와 타입 추론 기능을 적절히 활용하면, 오류를 사전에 방지하고 안전하면서도 효율적인 코드를 작성할 수 있다.
