impl Trait 문법과 트레이트 바운드 (trait bound)impl Trait란?impl Trait은 트레이트 바운드 (trait bound)의 간단한 문법 설탕임. fn foo() -> impl Iterator<Item = i32> {
vec![1, 2, 3].into_iter()
}
foo 함수는 Iterator<Item = i32>를 구현하는 타입을 반환. Iterator 트레이트를 구현한다"는 정보만 제공. impl Trait은 트레이트 바운드의 문법 설탕impl Trait을 쓰지 않는다면, 트레이트 바운드 (trait bound) 문법을 직접 사용해야 함. // `impl Trait` 사용
fn foo() -> impl Iterator<Item = i32> {
vec![1, 2, 3].into_iter()
}
// 위 코드를 트레이트 바운드로 표현하면:
fn foo2<T: Iterator<Item = i32>>() -> T {
vec![1, 2, 3].into_iter() // ❌ 에러 발생!
}
foo2의 경우, 반환 타입 T가 모든 Iterator<Item = i32> 타입이 될 수 있어야 하는데,impl Trait을 사용하면 컴파일러가 내부적으로 하나의 반환 타입으로 고정하여 처리할 수 있음. impl Trait 사용impl Trait 사용 가능 → 코드가 더 간결해짐. use std::fmt::Display;
// `impl Trait` 사용
fn print_display(value: impl Display) {
println!("{}", value);
}
// 위 코드를 트레이트 바운드로 표현하면:
fn print_display2<T: Display>(value: T) {
println!("{}", value);
}
impl Trait이 더 간결함. impl Trait과 dyn Trait 차이| 문법 | 사용 방식 | 차이점 |
|---|---|---|
impl Trait | 컴파일 타임에 타입이 결정됨 | 제네릭처럼 사용됨, 단일 타입만 가능 |
dyn Trait | 런타임에 타입이 결정됨 | 여러 타입을 처리할 수 있지만, 힙 할당과 동적 디스패치 필요 |
fn foo1() -> impl Iterator<Item = i32> { // ✅ 단일 타입 (컴파일 타임)
vec![1, 2, 3].into_iter()
}
fn foo2() -> Box<dyn Iterator<Item = i32>> { // ✅ 여러 타입 가능 (런타임)
Box::new(vec![1, 2, 3].into_iter())
}
impl Trait → 컴파일 타임에 타입이 고정됨 (빠름, 단일 타입만 가능). dyn Trait → 여러 타입을 처리할 수 있지만, 런타임 비용이 발생 (느림). impl Trait은 trait bound의 문법 설탕 → 코드가 더 간결해짐. impl Trait을 사용하면 타입을 노출하지 않고 트레이트만 지정 가능. impl Trait 사용 가능, T: Trait 문법과 같은 의미. impl Trait은 컴파일 타임에 타입이 결정되지만, dyn Trait은 런타임에 타입이 결정됨. 즉, impl Trait은 제네릭처럼 동작하면서 코드 가독성을 높이는 문법입니다!