12.4 Bounds
제네릭으로 동작할 때, 타입 매개변수는 종종 바인드 된 trait을 사용하여 타입 구현의 기능성을 규정해야 한다. 예시로서 다음의 예제는 Display
trait을 사용하여 출력하고자 하는데 그래서 T
는 Display
에 바인드 되어야 한다; 이에 따라, T
는 반드시 Display
를 구현해야 한다.
When working with generics, the type parameters often must use traits as bounds to
stipulate what functionality a type implements. For example, the following
example uses the trait Display
to print and so it requires T
to be bound
by Display
; that is, T
must implement `Display
// 반드시 `Display`를 구현해야 하는 제네릭 타입 `T`를
// 취하는 함수 `printer`를 정의한다.
fn printer<T: Display>(t: T) {
println!("{}", t);
}
제네릭을 타입에 바인드 시키는 제약은 바인드 되는 대상에 따른다. 이는: Bounding restricts the generic to types that conform to the bounds. That is:
struct S<T: Display>(T);
// 에러! `Vec<T>`는 `Display`를 구현하지 않았다.
// 이 특수 문장은 실패할 것이다.
let s = S(vec![1]);
바인딩의 다른 효과는 제네릭 인스턴스가 바인드에 지정된 trait의 [메소드]에 접근이 허용된다. 예를 들어: Another effect of bounding is that generic instances are allowed to access the methods of traits specified in the bounds. For example:
// 출력 마커를 구현한 trait: `{:?}`. use std::fmt::Debug; trait HasArea { fn area(&self) -> f64; } impl HasArea for Rectangle { fn area(&self) -> f64 { self.length * self.height } } #[derive(Debug)] struct Rectangle { length: f64, height: f64 } #[allow(dead_code)] struct Triangle { length: f64, height: f64 } // 제네릭 `T`는 `Debug`를 구현해야 한다. 타입에 관계 없이 // 이것은 제대로 작동한다. fn print_debug<T: Debug>(t: &T) { println!("{:?}", t); } // `T`는 `HasArea`를 구현해야 한다. 바인드 된 대상과 결합되는 모든 함수가 // `HasArea`의 함수 `area`에 접근할 수 있다. fn area<T: HasArea>(t: &T) -> f64 { t.area() } fn main() { let rectangle = Rectangle { length: 3.0, height: 4.0 }; let _triangle = Triangle { length: 3.0, height: 4.0 }; print_debug(&rectangle); println!("Area: {}", area(&rectangle)); //print_debug(&_triangle); //println!("Area: {}", area(&_triangle)); // ^ TODO: 이들의 주석을 제거해보세요. // | 에러! : `Debug` 혹은 `HasArea`를 구현하지 않음. }
추가로 주의할 점은, where
항목도 더 표현하고자 하는 경우에 바인드 되는 대상으로 적용하는데 사용될 수 있다.
As an additional note, where
clauses can also be used to apply bounds in
some cases to be more expressive.