🏷️

타입 시스템 — 동적 타입의 자유를 포기하면 얻는 것

Ruby의 duck typing vs Rust의 정적 타입 추론

Ruby에서 x = "hello"였다가 x = 42로 바꿔도 아무 문제없다. 메서드만 있으면 되니까(duck typing). Rust에서는 이게 불가능하다.

let x = "hello";  // 컴파일러가 &str로 추론
// x = 42;  // 컴파일 에러! expected &str, found integer

기본 타입들

Ruby의 Integer, Float, String 등이 Rust에서는 더 세분화된다.

Ruby Rust 설명
Integer i32, i64, u32, u64 부호/크기 명시
Float f32, f64 32비트/64비트
true/false bool 동일
String String, &str 두 종류 (별도 포스트)
nil 없음 (Option<T>) 별도 포스트
Symbol 없음 (enum 사용) 별도 포스트
Array Vec<T> 제네릭
Hash HashMap<K, V> 제네릭

i32는 32비트 부호 있는 정수, u64는 64비트 부호 없는 정수. Ruby에서는 이런 구분을 신경 쓸 일이 없었지만, Rust에서는 메모리 크기와 부호를 명시한다.

타입 추론

Rust는 타입을 안 써도 대부분 알아서 추론한다.

let x = 42;          // i32로 추론 (기본값)
let y = 3.14;         // f64로 추론 (기본값)
let name = "sehwa";   // &str로 추론
let nums = vec![1, 2, 3]; // Vec<i32>로 추론

명시가 필요한 경우도 있다. 컴파일러가 결정을 못 하는 상황이다.

// 이건 에러 — 42가 i32인지 u64인지 모름
let x = "42".parse(); // error: type annotations needed

// 이렇게 알려줘야 함
let x: i32 = "42".parse().unwrap();
// 또는
let x = "42".parse::<i32>().unwrap();  // turbofish 문법

::<i32>를 turbofish라고 부른다. 생김새가 물고기 같다고. Rust 커뮤니티 특유의 네이밍.

튜플과 배열

Ruby의 배열은 아무 타입이나 섞을 수 있다. [1, "hello", true] 가능. Rust의 Vec은 한 가지 타입만 담는다.

여러 타입을 묶고 싶으면 튜플을 쓴다.

let pair: (i32, &str) = (42, "hello");
println!("{}", pair.0);  // 42
println!("{}", pair.1);  // hello

Ruby에서 return a, b로 여러 값을 반환하는 패턴이 Rust에서는 튜플이다.

fn divide(a: f64, b: f64) -> (f64, f64) {
    (a / b, a % b)  // 몫과 나머지
}
let (quotient, remainder) = divide(10.0, 3.0);

타입 변환 — as와 From/Into

Ruby에서 42.to_s, "42".to_i로 자유롭게 변환한다. Rust에서는 두 가지 방법이 있다.

// 숫자 간 변환 — as (Ruby의 .to_i/.to_f에 가까움)
let x: i32 = 42;
let y: f64 = x as f64;

// 문자열 → 숫자 — parse (실패 가능하므로 Result 반환)
let n: i32 = "42".parse().unwrap();

// 숫자 → 문자열 — to_string
let s: String = 42.to_string();

as는 숫자 간 변환에서만 쓴다. 문자열 변환은 parse()to_string()을 쓴다. Ruby처럼 .to_i로 끝나는 게 아니라 Result를 반환하기 때문에, 변환 실패를 무시할 수 없다.

핵심 포인트

1

Rust의 기본 정수형은 i32, 부호/크기를 명시한다

2

타입 추론이 강력해서 대부분 명시할 필요 없다

3

여러 타입을 묶으려면 튜플 (i32, &str)을 사용한다

4

타입 변환은 as(숫자), parse()(문자열→숫자)로 명시적

장점

  • 타입 에러가 컴파일 타임에 잡힌다 — Ruby의 TypeError가 사라진다
  • IDE 자동완성이 완벽하게 작동한다 — Ruby보다 훨씬 정확

단점

  • Ruby의 자유로운 타입 전환이 안 되니 초반에 답답하다
  • i32와 i64를 더하려면 명시적 변환이 필요하다

사용 사례

성능 민감한 코드에서 i32 vs i64 선택이 중요할 때 외부 데이터(JSON, CSV) 파싱 시 타입 변환 처리