내장 타입과 변수: C# 개발자의 시각으로 보기
학습 목표: Rust의 변수 선언 방식과 가변성(Mutability) 모델을 C#의
var/const와 비교하여 명확히 이해합니다. 특히 C# 개발자가 가장 혼동하기 쉬운String과&str의 차이점을 정복하고, 타입 추론 및 캐스팅 메커니즘을 배웁니다.
1. 변수와 가변성 (Immutability by Default)
C#은 기본적으로 모든 변수가 가변적이지만, Rust는 **기본이 불변(Immutable)**입니다.
| C# 스타일 | Rust 스타일 | 의미 |
|---|---|---|
int x = 5; | let x = 5; | 불변: 한 번 설정하면 변경 불가 (C#의 readonly와 유사) |
int x = 5; x = 6; | let mut x = 5; x = 6; | 가변: mut 키워드로 명시해야 변경 가능 |
const int X = 5; | const X: i32 = 5; | 상수: 컴파일 타임 고정값 (반드시 타입 명시 필요) |
💡 변수 섀도잉 (Shadowing)
Rust에서는 같은 이름의 변수를 다시 선언할 수 있습니다. 이는 기존 변수를 '가리는' 효과를 내며, 타입 변환 시 유용합니다.
#![allow(unused)] fn main() { let input = "42"; // &str 타입 let input: i32 = input.parse().unwrap(); // 이제 같은 이름의 i32 타입 변수입니다. }
2. 데이터 타입 매핑
| C# 타입 | Rust 타입 | 설명 |
|---|---|---|
int, uint | i32, u32 | 32비트 정수 (표준) |
long, ulong | i64, u64 | 64비트 정수 |
float, double | f32, f64 | 부동 소수점 |
bool | bool | 논리값 |
char | char | 4바이트 유니코드 (C#은 2바이트 UTF-16) |
IntPtr, UIntPtr | isize, usize | 포인터 크기 정수 (배열 인덱스 등에 사용) |
3. 문자열의 두 얼굴: String vs &str
C#은 string 하나로 모든 것을 처리하지만, Rust는 메모리 효율을 위해 두 가지를 구분합니다.
String: 힙에 할당된 가변 문자열. 데이터를 소유합니다. (C#의StringBuilder나 힙에 있는string과 유사)&str: 문자열의 일부분을 가리키는 참조(슬라이스). 데이터를 빌려옵니다. (C#의ReadOnlySpan<char>와 유사)
#![allow(unused)] fn main() { let s1: &str = "Hello"; // 리터럴은 슬라이스입니다. let s2: String = s1.to_string(); // 슬라이스를 소유권이 있는 String으로 변환 let s3: &str = &s2; // String의 데이터를 다시 빌려오기 (비용 없음) }
4. 타입 변환 (엄격한 규칙)
Rust에는 C#과 같은 암시적 숫자 변환이 없습니다. 작은 타입에서 큰 타입으로 옮길 때도 반드시 명시적으로 선언해야 합니다.
as캐스팅:let x = 42_u8 as u32;(확대/축소 변환)From/Into:let x: u32 = 42_u8.into();(안전한 표준 변환)TryFrom/TryInto: 실패 가능성이 있는 변환 시Result반환 (예:u32를u8로 바꿀 때)
💡 실무 팁: dbg! 매크로 활용
C#에서 Console.WriteLine으로 값을 확인하듯, Rust에서는 dbg!(variable)를 써보세요. 파일명, 줄 번호와 함께 변수의 값을 stderr에 출력하고 그 값을 다시 반환하므로 코드 어디든 삽입하기 편리합니다.