제네릭을 정적 디스패치 로 썼어: 컴파일러가 타입마다 특화 복사본을 찍어내. 가끔 반대가 필요해 — 공유 trait 뒤에 여러 다른 타입을 담는 한 컬렉션. 그게 동적 디스패치, dyn 으로.
정적 디스패치 (제네릭)
제네릭 fn render<T: Draw>(item: &T) 는 컴파일 타임에 해결돼: 각 구체 T 가 자기 컴파일된 버전을 갖고, 메서드 호출이 직접적이야 — 여느 함수 호출만큼 빨라. 비용은 코드 크기 (타입마다 한 복사본) 랑 한 호출 지점이 정확히 한 타입에만 통한다는 제약.
동적 디스패치 (dyn Trait)
&dyn Draw 나 Box<dyn Draw> 는 트레잇 객체 야: 어떤 값으로의 포인터 + 그 trait 메서드 테이블 (vtable) 로의 포인터. 구체 타입은 지워지고; 메서드는 런타임에 조회돼. 이게 Vec<Box<dyn Draw>> 가 원, 사각형, 텍스트를 한꺼번에 담게 하는 거야 — 사용마다 한 타입을 고정하는 제네릭으론 불가능.
호출마다-한-타입 속도엔 제네릭; 한-컬렉션에-여러-타입 유연성엔
dyn. 기본은 제네릭으로 손 뻗어 — zero-cost 니까. 진짜로 이종 컬렉션이 필요하거나 다른 타입 값을 한 인터페이스 뒤에 저장해야 할 때 dyn Trait 으로 손 뻗고, 작은 vtable 간접을 받아들여.왜 보통 Box 가 끼냐
트레잇 객체는 알려진 크기가 없어 — 원이랑 긴 문자열은 바이트가 다르거든 — 그래서 스택에 직접 못 저장해. 포인터 뒤에 둬: Box<dyn Trait> (소유, 힙) 나 &dyn Trait (빌림). Box 가 트레잇 객체한테 고정 크기 핸들을 줘, 바로 Smart Pointers 트랙이 다루는 거야.