트레잇 구현하기(impl Trait
)
트레잇 바운드와 유사하게 impl Trait
문법은 함수의 인자와 반환값에도 적용 가능합니다:
use std::fmt::Display; fn get_x(name: impl Display) -> impl Display { format!("Hello {name}") } fn main() { let x = get_x("foo"); println!("{x}"); }
impl Trait
를 이용하면 이름이 없는 타입을 다룰 수 있습니다.
impl Trait
는 어디에 사용되었느냐에 따라 의미가 조금씩 다릅니다.
-
함수 인자의 타입으로 사용되었을 경우에는
impl Trait
는 트레잇 경계가 있는 익명의 제네릭 타입을 의미합니다. -
리턴 타입으로 사용되었을 경우에는, 그 트레잇을 구현하는 구체적인 타입인데, 타입 이름을 프로그래머가 짓지 않았다는 것을 의미합니다. 이는 그 구체적인 타입 이름을 API로 공개하고 싶지 않은 경우에 유용합니다.
함수가 리턴되는 곳에서의 타입 추론은 어렵습니다. 어떤 함수의 리턴 타입이
impl Foo
로 선언되어 있을 경우, 그 함수가 실제로 리턴하는 타입은 소스 코드 상 어디에도 나타나 있지 않습니다.collect<B<() -> B
와 같이 제너릭 타입을 리턴하는 함수는B
를 만족하는 어떤 타입도 리턴할 수 있습니다. 이 경우, 호출하는 측에서는let x: Vec<_> = foo.collect()
나 터보피시 문법을 써서foo.collect::<Vec<_>>()
와 같이 리턴 타입을 명시적으로 써 주어야 할 수도 있습니다.
이 예시는 impl Display
가 두번 사용 되었다는 점에서 훌륭합니다. 여기서 중요한 것은 이 두 impl Display
가 실제로 같은 타입일 필요가 없다는 것입니다. 만약 T: Display
로 트레잇 경계를 정하고 입력 파라메터와 리턴 값의 타입을 모두 T
로 했다면, 이는 입력과 리턴값이 같은 타입임을 강제합니다. 이렇게 했다면 위의 예제는 동작하지 않았을 것입니다. 왜냐하면, 입력 값의 타입이 format!
이 리턴하는 타입과 같지 않을 가능성이 높기 때문입니다. 만약 : Display
문법을 사용하고 싶다면 독립적인 제네릭 매개변수가 두 개가 필요합니다.