<트레이트(trait)>
: 타입들이 공통적으로 갖는 동작을 추상적으로 정의한 것입니다. trait bound를 이용하면 어떤 제네릭 타입 자리에 특정한 동작의 타입이 오도록 명시할 수 있습니다.
- 트레이트 구현
trait를 정의하고, 어떤 구조체(NewArticle)가 trait를 구현하도록 지정한 예시 코드입니다. trait의 메서드는 선언부만 정의할수도, 구현체까지 정의할 수도 있으며, 기본 동작을 유지할지 override할지 선택할 수 있습니다. 예시 코드에서는 트레이트에서 summarize() 함수의 선언부만 정의한 후, NewArticle에서 오버라이드했습니다.
// 신문 기사를 요약해주는 trait 구현
trait Summary {
// 선언부만 정의
fn summarize(&self) -> String;
}
// 기사 정보를 가진 구조체
struct NewArticle {
pub headline: String,
pub author: String,
pub content: String,
}
impl Summary for NewArticle {
// 여기서 구현
fn summarize(&self) -> String {
format!("{} by {} ({})", self.headline, self.author, self.content)
}
}
NewArticle 구조체의 인스턴스인 article을 정의한 후, summariz() 메서드를 사용할 수 있습니다.
fn main() {
let article = NewArticle {
headline: String::from("headline"),
author: String::from("me"),
content: String::from("content"),
};
println!("{}", article.summarize()); // headline by me (content) 출력
}
- 매개변수로서의 트레이트
위에서 작성한 예시코드에 이어서, item 매개변수가 Summary 트레이트를 사용하고 있다면 summarize 메서드를 호출하는 notify 함수입니다.
fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
fn main() {
let article = NewArticle {
headline: String::from("headline"),
author: String::from("me"),
content: String::from("content"),
};
notify(&article); // Breaking news! headline by me (content) 출력
}
만약 다음과 같이 Summary 트레이트를 구현하지 않은 값을 매개변수로 넣을 경우 컴파일 에러가 발생합니다 : error[E0277]: the trait bound `Tweet: Summary` is not satisfied
struct Tweet {
username: String,
content: String,
reply: bool,
retweet: bool,
}
fn main() {
let tweet = Tweet {
username: String::from("name"),
content: String::from("content2"),
reply: true,
retweet: false,
};
notify(&tweet); // 에러 발생
}
- 트레이트 바운드 문법
위에서 예시로 들었던 notify() 함수에 트레이트 바운드 문법을 적용시키면 다음과 같이 변합니다.
// 적용 전
fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// 적용 후
fn notify2<T: Summary>(item: &T){
println!("Breaking news! {}", item.summarize());
}
- + 구문으로 트레이트 바운드를 여럿 지정하기
트레이트 바운드는 다음과 같이 여러개 지정할 수 있습니다.
fn notify(item: &(impl Summary + Display)) {
// ...
}
fn notify2<T: Summary + Display>(item: &T) {
// ...
}
- where 조항으로 트레이트 바운드 정리
트레이트 바운드가 너무 많아지면 가독성을 해치므로 where을 사용해서 정리할 수 있습니다.
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,
{
- 트레이트를 구현하는 타입 반환
fn returns_summarizable() -> impl Summary {
NewArticle {
headline: String::from("headline"),
author: String::from("me"),
content: String::from("content"),
}
}
fn main() {
println!("{}", returns_summarizable().summarize());
}
- 트레이트 바운드를 사용해서 조건부로 메서드 구현
x, y 필드를 가진 Pair 구조체는 new() 메서드를 사용해 새로운 인스턴스를 생성할 수 있습니다.
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
여기서 T 타입을 정렬해서 크기비교를 할 수 있게 해주는 PartialOrd 트레이트와 출력 가능하게 해주는 Display 트레이트를 구현한 cmp_display() 메서드입니다.
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}
let pair = Pair::new(4,5);
pair.cmp_display(); // The largest member is y = 5 출력
출처 : https://rust-kr.github.io/doc.rust-kr.org/ch10-02-traits.html
'[Rust]' 카테고리의 다른 글
[Rust] 라이프타임(lifetime) (0) | 2023.08.19 |
---|---|
[Rust] 제네릭 타입 (0) | 2023.08.17 |
[Rust] 에러 처리 (0) | 2023.08.16 |
[Rust] match 연산자 (0) | 2023.08.15 |
[Rust] 컬렉션(Collection) (0) | 2023.08.14 |