rust Trait Bound

agnusdei·2025년 2월 6일

Rust에서 Trait Bound는 제네릭 타입이 특정 트레이트(Trait)를 구현하도록 제한하는 방식입니다. 이를 통해 컴파일러가 해당 타입이 특정 메서드를 사용할 수 있음을 보장할 수 있습니다.

1. 기본적인 Trait Bound 사용

Rust의 제네릭(Generic)은 기본적으로 어떤 타입이든 받을 수 있지만, 특정 기능이 필요할 경우 trait bound를 사용하여 제약을 설정할 수 있습니다.

fn print<T: ToString>(item: T) {
    println!("{}", item.to_string());
}

위 함수에서 T: ToStringT가 반드시 ToString 트레이트를 구현해야 함을 의미합니다. 따라서 print(42)처럼 숫자를 넣어도 ToString을 구현하고 있기 때문에 정상적으로 작동합니다.

2. 여러 개의 Trait Bound 사용

여러 개의 트레이트를 적용하려면 + 연산자를 사용합니다.

fn print_and_clone<T: ToString + Clone>(item: T) {
    let cloned = item.clone(); // Clone 트레이트가 필요함
    println!("{}", cloned.to_string()); // ToString 트레이트가 필요함
}

3. where 절을 이용한 Trait Bound

여러 개의 제약이 있을 경우 where을 사용하면 가독성이 좋아집니다.

fn print_and_clone<T>(item: T)
where
    T: ToString + Clone,
{
    let cloned = item.clone();
    println!("{}", cloned.to_string());
}

4. impl Trait를 이용한 Trait Bound

Rust 1.26 이후부터는 impl Trait을 사용할 수 있습니다.

fn print(item: impl ToString) {
    println!("{}", item.to_string());
}

이는 T: ToString과 동일한 역할을 하며, 가독성이 좋아지는 장점이 있습니다.

5. dyn Trait과 차이점

  • impl Trait: 정적 디스패치(static dispatch) 사용, 컴파일 타임에 결정됨.
  • dyn Trait: 동적 디스패치(dynamic dispatch) 사용, 런타임에 결정됨.
fn print_dyn(item: &dyn ToString) {
    println!("{}", item.to_string());
}

위와 같이 dyn Trait을 사용하면 &dyn ToString은 런타임에 타입이 결정되며, vtable을 사용하여 메서드를 호출합니다.

6. Default와 같은 트레이트를 활용한 제네릭 구조체 예제

Trait Bound는 구조체에서도 사용할 수 있습니다.

struct Container<T: Default + Clone> {
    value: T,
}

impl<T: Default + Clone> Container<T> {
    fn new() -> Self {
        Container { value: T::default() }
    }
}

위 코드에서 T: Default + Clone을 통해 TDefaultClone을 구현해야 Container<T>를 사용할 수 있습니다.


정리

  • T: Trait: 기본적인 트레이트 바운드 문법
  • T: Trait1 + Trait2: 여러 개의 트레이트 바운드 적용
  • where T: Trait1 + Trait2: 가독성을 위한 where 절 사용
  • impl Trait: 간결한 표현을 위해 사용
  • dyn Trait: 런타임에서 결정되는 동적 디스패치
profile
DevSecOps, Pentest, Cloud(OpenStack), Develop, Data Engineering, AI-Agent

0개의 댓글