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.