C.W.K.
Stream
Lesson 05 of 07 · published

dyn vs impl: 동적 & 정적 디스패치

~12 min · traits, dyn, trait-objects, dispatch

Level 0Rust 호기심러
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

제네릭을 정적 디스패치 로 썼어: 컴파일러가 타입마다 특화 복사본을 찍어내. 가끔 반대가 필요해 — 공유 trait 뒤에 여러 다른 타입을 담는 한 컬렉션. 그게 동적 디스패치, dyn 으로.

정적 디스패치 (제네릭)

제네릭 fn render<T: Draw>(item: &T) 는 컴파일 타임에 해결돼: 각 구체 T 가 자기 컴파일된 버전을 갖고, 메서드 호출이 직접적이야 — 여느 함수 호출만큼 빨라. 비용은 코드 크기 (타입마다 한 복사본) 랑 한 호출 지점이 정확히 한 타입에만 통한다는 제약.

동적 디스패치 (dyn Trait)

&dyn DrawBox<dyn Draw>트레잇 객체 야: 어떤 값으로의 포인터 + 그 trait 메서드 테이블 (vtable) 로의 포인터. 구체 타입은 지워지고; 메서드는 런타임에 조회돼. 이게 Vec<Box<dyn Draw>> 가 원, 사각형, 텍스트를 한꺼번에 담게 하는 거야 — 사용마다 한 타입을 고정하는 제네릭으론 불가능.

호출마다-한-타입 속도엔 제네릭; 한-컬렉션에-여러-타입 유연성엔 dyn. 기본은 제네릭으로 손 뻗어 — zero-cost 니까. 진짜로 이종 컬렉션이 필요하거나 다른 타입 값을 한 인터페이스 뒤에 저장해야 할 때 dyn Trait 으로 손 뻗고, 작은 vtable 간접을 받아들여.

왜 보통 Box 가 끼냐

트레잇 객체는 알려진 크기가 없어 — 원이랑 긴 문자열은 바이트가 다르거든 — 그래서 스택에 직접 못 저장해. 포인터 뒤에 둬: Box<dyn Trait> (소유, 힙) 나 &dyn Trait (빌림). Box 가 트레잇 객체한테 고정 크기 핸들을 줘, 바로 Smart Pointers 트랙이 다루는 거야.

Code

트레잇 객체로 만든 이종 컬렉션·rust
trait Draw {
    fn draw(&self) -> String;
}

struct Circle;
struct Square;
impl Draw for Circle { fn draw(&self) -> String { "O".into() } }
impl Draw for Square { fn draw(&self) -> String { "[]".into() } }

fn main() {
    // 동적 디스패치: 한 Vec 이 다른 구체 타입들을 담음
    let shapes: Vec<Box<dyn Draw>> = vec![Box::new(Circle), Box::new(Square)];
    for s in &shapes {
        println!("{}", s.draw()); // 메서드가 vtable 통해 런타임에 해결됨
    }
}

External links

Exercise

area(&self) -> f64 를 가진 Shape trait 을 정의해. Circle 이랑 Rectangle 에 구현해. 둘 다 담은 Vec<Box<dyn Shape>> 를 짓고 루프로 넓이를 합산해. 그다음 제네릭 Vec<T> 로 똑같이 쓰려 하고 왜 둘 다 못 담는지 설명해.
Hint
Vec<T> 는 구체 T 하나를 고정해서 Circle 이랑 Rectangle 을 같이 못 담아. Vec<Box<dyn Shape>> 는 구체 타입을 트레잇 객체 뒤로 지워서 섞이게 해 — 런타임 디스패치 비용으로.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.