지금까진 한 타입에만 통하는 코드를 썼어. 제네릭은 한 번 써서 여러 타입에 통하게 해줘 — Rust 의 컴파일 타임 타입 안전을 포기하지 않고.
제네릭이 푸는 문제
i32 좌표 둘짜리 Point 를 상상해. 이제 f64 좌표짜리가 필요해. 타입만 다르게 struct 를 복붙하는 게 제네릭이 죽이려고 존재하는 그 중복이야. 제네릭 파라미터 T 는 '나중에 고를 어떤 타입' 을 대신하고, 컴파일러가 네가 실제로 쓰는 각 구체 타입마다 특화된 버전을 찍어내.
제네릭 struct 와 메서드
struct Point<T> { x: T, y: T } 는 어떤 타입 T 에든 통해. 메서드는 impl<T> Point<T> 에 들어가고. 각 사용 지점에서 Point<i32> 와 Point<f64> 는 구별되고 완전히 타입 검사된 타입이야. 런타임 비용은 없어: 제네릭은 monomorphize 돼 — 컴파일러가 타입마다 구체 코드를 생성하니, 각 버전을 손으로 쓴 것만큼 빠르게 돌아.
제네릭은 zero-cost 야. Java 의 type erasure 나 Python 의 duck typing 과 달리 Rust 는 monomorphize 해: 각 구체 인스턴스화가 자기 컴파일된 코드가 돼. 제네릭의 재사용성을 손으로 특화한 타입의 속도로 얻어 — boxing 도, 런타임 디스패치도 없이.
한계, 그리고 다음에 올 것
맨 T 는 저장하고 move 할 순 있지만 많은 걸 못 해 — T 둘을 더하거나 하나를 출력 못 해, 모든 타입이 그걸 지원하진 않으니까. 'T 는 더할 수 있어야 해' 나 'T 는 출력 가능해야 해' 라고 말하려면 trait bound 가 필요해 — 그리고 trait 이 다음 트랙 전부야. 제네릭과 trait 은 한 아이디어의 두 반쪽이야; 방금 첫 반쪽을 만난 거야.