트레잇 구현하기(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 문법을 사용하고 싶다면 독립적인 제네릭 매개변수가 두 개가 필요합니다.