트레이트 경계 문법
Coddy Rust 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 40번째.
지금까지 트레이트를 정의하고 구조체에 구현하는 방법을 배웠습니다. 또한 유연한 코드를 작성하기 위해 제네릭을 사용해 보았습니다. 이제 이러한 개념을 결합할 시간입니다. 트레이트를 사용하여 제네릭 function이 accept할 수 있는 타입을 제한해 보겠습니다.
매개변수에서 특정 method를 호출해야 하는 generic function을 생각해 보세요. 아무런 제약이 없으면 Rust는 T type에 해당 method가 있다는 것을 보장할 수 없습니다:
fn print_info<T>(item: T) {
println!("{}", item.summarize()); // 오류! T에는 summarize()가 없을 수 있습니다
}
해결책은 trait bound입니다. 제네릭 매개변수 뒤에 : TraitName을 추가하면 T가 해당 트레이트를 구현해야 한다는 것을 Rust에 알릴 수 있습니다.
trait Summary {
fn summarize(&self) -> String;
}
fn print_info<T: Summary>(item: T) {
println!("{}", item.summarize()); // 이제 Rust는 이 메서드가 존재한다는 것을 압니다
}
<T: Summary> 구문은 "T는 Summary를 implements하는 모든 타입이다"라는 의미로 읽힙니다. 이제 이 function은 필요한 동작을 갖는 타입만 accept합니다. Summary를 implements하지 않는 타입을 전달하려고 하면 컴파일러는 명확한 Error와 함께 이를 거부합니다.
이 패턴은 필요한 동작에 대한 접근 권한을 유지하면서도 generic 코드를 작성할 수 있게 해 주기 때문에 강력합니다. 여러분의 function은 유연하게 유지되며, any type과 함께 작동하지만, 필요한 동작을 제공하는 type만 사용할 수 있습니다.
챌린지
쉬움trait bound를 사용하여 올바르게 형식이 지정된 메시지만 전송될 수 있도록 보장하는 알림 시스템을 만들어 봅시다! 특정 trait을 구현하는 모든 타입을 accept하는 generic function을 만들면서, trait bound가 generic parameter를 제한하는 방식을 보여 줍니다.
코드를 두 개의 파일로 구성합니다:
notification.rs:message이라는 method를 가진 publicNotifytrait을 정의합니다. 이 method는&self를 받고String을 returns합니다. 그런 다음 이 trait을 구현하는 두 개의 public struct를 만듭니다:Email: publicsubjectfield(String)을 가집니다. 이messagemethod는Email: {subject}를 returns해야 합니다.SMS: publiccontentfield(String)을 가집니다. 이messagemethod는SMS: {content}를 returns해야 합니다.
Notifytrait을 구현하는 모든 타입T를 accept하는 public generic functionsend_notification을 만듭니다. 이 function은 item에서message()를 calling한 result를 출력해야 합니다.main.rs: notification module을 가져오고 제공된 inputs를 사용하여Email과SMSinstance를 각각 만듭니다. generic function이Notify를 구현하는 모든 타입과 함께 작동한다는 것을 보여 주기 위해 각각에send_notification을 calling합니다.
여기서 핵심은 send_notification이 자신이 받는 구체적인 타입을 알지 못한다는 점입니다. 해당 타입이 message를 생성할 수 있다는 것만 알고 있습니다. trait bound T: Notify는 이 기능을 보장합니다.
출력에는 두 알림이 모두 전송된 결과가 표시되어야 합니다:
Email: {subject}
SMS: {content}예를 들어 inputs가 Meeting Tomorrow와 On my way!인 경우:
Email: Meeting Tomorrow
SMS: On my way!두 개의 inputs를 받습니다. email subject와 SMS content입니다.
직접 해보기
mod notification;
use notification::{Email, SMS, send_notification};
fn main() {
// 입력 읽기
let mut subject = String::new();
std::io::stdin().read_line(&mut subject).expect("Failed to read line");
let subject = subject.trim().to_string();
let mut content = String::new();
std::io::stdin().read_line(&mut content).expect("Failed to read line");
let content = content.trim().to_string();
// TODO: subject로 Email 인스턴스 생성
// TODO: content로 SMS 인스턴스 생성
// TODO: email로 send_notification 호출
// TODO: sms로 send_notification 호출
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Rust 컴파일러