🧩

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

참고 자료