🧩
Trait과 제네릭 — Rust의 다형성
인터페이스 + 제네릭이 합쳐진 Rust의 추상화 도구
Trait은 "이 타입은 이런 동작을 할 수 있다"를 정의한다. Java의 interface와 비슷하지만, 기존 타입에 나중에 trait을 구현(impl)할 수 있다는 점이 다르다.
trait Summary {
fn summarize(&self) -> String;
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, self.content[..20])
}
}
제네릭 함수에서 where T: Summary 같은 trait bound를 쓰면, T가 Summary를 구현한 타입이라는 걸 보장한다. 컴파일러가 각 구체 타입별로 함수를 별도 생성(monomorphization)하기 때문에 런타임에 가상 함수 테이블(vtable) 비용이 없다.
dyn Trait을 쓰면 런타임 다형성(동적 디스패치)도 가능하다. 이 경우 vtable을 통한 간접 호출이 발생한다.
핵심 포인트
1
trait으로 공통 동작(메서드 시그니처)을 정의
2
impl Trait for Type으로 구체 타입에 구현
3
제네릭 + trait bound로 컴파일 타임 다형성 (정적 디스패치)
4
dyn Trait으로 런타임 다형성 필요 시 동적 디스패치
장점
- ✓ 제로 코스트 추상화 — 제네릭은 monomorphization으로 인라인
- ✓ 기존 타입에 후속 구현 가능 (orphan rule 범위 내)
단점
- ✗ monomorphization으로 바이너리 크기가 커질 수 있다
- ✗ trait 제약이 복잡해지면 where절이 길어진다
사용 사례
직렬화 — serde의 Serialize/Deserialize trait
비동기 런타임 — Future trait 기반의 async/await