예시 코드 먼저 보자
// 동적 디스패치와 정적 디스패치(제네릭) 비교 예시
trait Trait {
fn do_something(&self);
}
struct A;
struct B;
impl Trait for A {
fn do_something(&self) {
println!("A is doing something");
}
}
impl Trait for B {
fn do_something(&self) {
println!("B is doing something");
}
}
// 동적 디스패치
fn execute_trait_dyn(obj: &dyn Trait) {
obj.do_something();
}
// 정적 디스패치
fn execute_trait_static<T: Trait>(obj: &T) {
obj.do_something();
}
fn main() {
let a = A;
let b = B;
// 동적 디스패치
execute_trait_dyn(&a);
execute_trait_dyn(&b);
// 정적 디스패치
execute_trait_static(&a);
execute_trait_static(&b);
}
예시 코드에서 fn execute_trait(obj: &dyn Trait) {}와 fn execute_trait<T: Trait>(obj: &T) {}는 비슷해 보이지만 중요한 차이가 있다.
dyn 사용)fn execute_trait<T: Trait>(obj: &T) {}
&dyn Trait 타입의 참조를 인자로 받는다. dyn Trait은 동적 디스패치 trait 객체를 나타내며, 이로 인해 런타임에 메서드 호출이 실제 타입에 따라 결정된다. 이는 정적 디스패치에 비해 추가적인 비용이 발생하고, 컴파일러가 최적화를 수행하기 어렵다.`fn execute_trait(obj: &dyn Trait) {}
T를 인자로 받는다. T는 Trait을 구현해야 하며, 컴파일 타임에 T의 실제 타입이 결정된다. 따라서 메서드 호출이 정적으로 결정된다.dyn): 런타임에 메서드 호출이 결정됨. 유연성을 제공하지만, 런타임 오버헤드 발생.성능이 중요하면 정적 디스패치(제네릭) 쓰고, 유연성이 중요하면 동적 디스패치 쓰자.