트레이트 벡터
Coddy Rust 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 46번째.
Box<dyn Trait>을 사용하면 하나의 변수가 서로 다른 타입을 보유할 수 있다는 것을 살펴보았습니다. 여러 컬렉션을 결합하면 진정한 강력함이 드러납니다. 하나의 벡터에 여러 서로 다른 타입을 저장할 수 있습니다.
일반 벡터에서는 모든 요소가 같은 타입이어야 합니다. Vec<Dog>에 고양이도 포함되도록 할 수는 없습니다. 하지만 트레이트 객체를 사용하면 공통 트레이트를 구현하는 무엇이든 담을 수 있는 벡터를 만들 수 있습니다.
trait Speak {
fn speak(&self) -> String;
}
struct Dog;
struct Cat;
struct Bird;
impl Speak for Dog {
fn speak(&self) -> String { String::from("Woof!") }
}
impl Speak for Cat {
fn speak(&self) -> String { String::from("Meow!") }
}
impl Speak for Bird {
fn speak(&self) -> String { String::from("Tweet!") }
}
fn main() {
let animals: Vec<Box<dyn Speak>> = vec![
Box::new(Dog),
Box::new(Cat),
Box::new(Bird),
];
}
Vec<Box<dyn Speak>> 타입은 "박싱된 트레이트 객체의 벡터"를 의미합니다. 각 요소는 Speak을 구현하는 무언가를 가리키는 Box입니다. 실제 타입은 서로 다를 수 있습니다. 각 값을 벡터에 추가할 때 Box::new()로 감쌉니다.
이 패턴은 UI 구성 요소, 게임 엔터티 또는 플러그인 시스템처럼 서로 관련되어 있지만 다른 객체의 컬렉션을 관리해야 하는 유연한 시스템을 구축하는 데 필수적입니다.
챌린지
쉬움다양한 유형의 알림을 처리할 수 있는 알림 시스템을 만들어 봅시다! 여러 알림 유형, 이메일, SMS 메시지 및 푸시 알림을 저장하는 컬렉션을 만들고, 트레이트 객체를 사용하여 이 모든 것을 하나의 벡터에 담게 됩니다.
코드를 두 파일로 구성합니다.
notifications.rs:&self를 받고 전송되는 알림을 설명하는String을 반환하는send메서드를 포함한 publicNotify트레이트를 Define합니다. 그런 다음 세 개의 public 구조체를 만듭니다.Email: publicrecipientfield(String)을 가집니다.send는Email to: {recipient}를 반환해야 합니다.Sms: publicphonefield(String)을 가집니다.send는SMS to: {phone}을 반환해야 합니다.Push: publicdevicefield(String)을 가집니다.send는Push to: {device}를 반환해야 합니다.
main.rs: notifications 모듈을 가져오고 세 알림 유형을 모두 담는Vec<Box<dyn Notify>>유형의 벡터를 만듭니다. 제공된 inputs를 사용하여 각 알림 유형을 하나씩 만들고, 순서대로 (Email, Sms, Push) 벡터에 Add한 다음 벡터의 first element에서send()를 calling한 result를 출력합니다.
여기서 핵심 개념은 Email, Sms, Push가 completely different 구조체임에도 불구하고 Notify 트레이트를 공유하기 때문에 모두 같은 벡터에 함께 들어갈 수 있다는 것입니다. 각 element는 트레이트 객체를 만들기 위해 Box::new()로 감쌉니다.
출력에는 first notification이 표시되어야 합니다.
Email to: {recipient}예를 들어 inputs가 alice@example.com, 555-1234, iPhone-12인 경우:
Email to: alice@example.com세 개의 inputs를 받습니다. email recipient, phone number, device name입니다.
직접 해보기
mod notifications;
use notifications::{Notify, Email, Sms, Push};
fn main() {
// 입력 읽기
let mut recipient = String::new();
std::io::stdin().read_line(&mut recipient).expect("Failed to read line");
let recipient = recipient.trim().to_string();
let mut phone = String::new();
std::io::stdin().read_line(&mut phone).expect("Failed to read line");
let phone = phone.trim().to_string();
let mut device = String::new();
std::io::stdin().read_line(&mut device).expect("Failed to read line");
let device = device.trim().to_string();
// TODO: 다양한 알림 유형을 담기 위해 Vec<Box<dyn Notify>> 생성
// TODO: 입력을 사용하여 Email, Sms, Push 인스턴스 생성
// TODO: Box::new()를 사용하여 순서대로 (Email, Sms, Push) 벡터에 추가
// TODO: 첫 번째 요소에서 send() 호출 결과 출력
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Rust 컴파일러