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가 필요하지 않으며 어떠한 힙 할당도 하지 않게 됨