
pub trait Summarizable {
fn summary(&self) -> String;
}
summary 메소드에 의해 제공되는 동작으로 구성된 Summarizable trait의 정의summary를 정확히 동일한 시그니처로 정의되도록 강제함pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summarizable for NewsArticle {
fn summary(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summarizable for Tweet {
fn summary(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summary());
Summarizable trait과 NewsArticle 및 Tweet 타입을 동일한 [lib.rs](http://lib.rs) 내에 정의했기 때문에 모두 동일한 스코프 내에 있음lib.rs가 aggregator라고 불리는 crate에 대한 것이고 추가로 WeatherForecast 구조체에 대해 Summarizable을 구현하길 원한다면 Summarizable trait을 스코프로 가져와야 함extern crate aggregator;
use aggregator::Summarizable;
struct WeatherForecast {
high_temp: f64,
low_temp: f64,
chance_of_precipitation: f64,
}
impl Summarizable for WeatherForecast {
fn summary(&self) -> String {
format!("The high will be {}, and the low will be {}. The chance of
precipitation is {}%.", self.high_temp, self.low_temp,
self.chance_of_precipitation)
}
}
Summariable trait을 정의할 때 pub 키워드를 사용했기 때문에 Summariable은 공개 트레잇Vec에 대한 Display 트레잇 구현 불가능. 둘 다 표준 라이브러리 내에 정의되어 있기 때문aggregator crate 기능의 일부로서 Tweet과 같은 커스텀 타입에 대한 Display 트레잇 구현은 가능. Vec에 대한 Summarizable 구현 또한 가능 ⇒ orphan rule (고아 규칙. 부모 타입이 존재하지 않기 때문)pub trait Summarizable {
fn summary(&self) -> String {
String::from("(Read more...)")
}
}
impl 블록을 명시impl Summarizable for NewsArticle {}
author_summary만 정의하면 됨pub trait Summarizable {
fn author_summary(&self) -> String;
fn summary(&self) -> String {
format!("(Read more from {}...)", self.author_summary())
}
}
impl Summarizable for Tweet {
fn author_summary(&self) -> String {
format!("@{}", self.username)
}
}
item 상에서 summary 메소드를 호출 하는 함수 notify를 정의한 것. 이때 item은 Generic Type T 값pub fn notify<T: Summarizable>(item: T) {
println!("Breaking news! {}", item.summary());
}
item 상에서 summary를 호출하기 위해서 T에 대한 Trait Bound를 사용해 item이 반드시 Summarizable 트레잇을 구현한 타입이어야 함을 특정+ 사용 시 하나의 Generic Type에 대해 여러 개의 Trait Bound 특정 가능T: Summarizable + Display라면 T가 Summariable과 Display 둘 다 구현한 어떤 타입이어야 함을 의미fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {
where 절 사용 가능fn some_function<T, U>(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
{
largest 함수 고치기largest 함수에 trait bound를 사용해 에러를 고쳐봅시다.fn largest<T>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
실행결과:
error[E0369]: binary operation `>` cannot be applied to type `T`
|
5 | if item > largest {
| ^^^^
|
note: an implementation of `std::cmp::PartialOrd` might be missing for `T`
T의 두 값을 비교하는 연산자는 표준 라이브러리 트레잇인 std::cmp::PartialOrd 상에 기본 메소드로 정의되어 있으므로 T에 대한 trait bound 내에 PartialOrd 특정 필요i32와 char와 같은 타입들은 스택에 저장될 수 있으며 이 타입들은 Copy 트레잇을 구현하고 있음Copy가 구현된 타입들을 가지고 호출하도록 가정한다면 T의 trait bound에 Copy 또한 추가use std::cmp::PartialOrd;
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);
println!("The largest number is {}", result);
let chars = vec!['y', 'm', 'a', 'q'];
let result = largest(&chars);
println!("The largest char is {}", result);
}
Copy trait을 구현한 타입에 대한 것으로 제한하길 원치 않는다면, T가 Copy 대신 Clone trait bound를 갖도록 명시하여 함수가 소유권을 갖도록 할 수 있음clone 함수 사용은 더 많은 힙 할당을 할 수 있어 많은 양의 데이터에 대해서 동작이 느릴 수 있음을 주의T 값에 대한 참조자(&T)를 반환하도록 할 수도 있음Clone이나 Copy trait bound가 필요하지 않으며 어떠한 힙 할당도 하지 않게 됨