트레이트 구현하기
Coddy Rust 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 30번째.
이제 트레이트를 정의하는 방법을 알았으니, 구조체가 그 계약을 충족하도록 만드는 방법을 살펴보겠습니다. 트레이트를 구현하는 것은 추상적인 요구사항을 구체적인 동작과 연결합니다.
구문은 impl TraitName for StructName을 사용합니다:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
impl Speak for Dog 블록은 Rust에게 Dog가 Speak 트레이트를 구현하고 있음을 알려줍니다. 내부에서 실제 메서드 본문을 제공합니다. 이곳이 개가 어떻게 말하는지를 정의하는 곳입니다.
여러 타입이 동일한 트레이트를 구현할 때 트레이트의 강력함이 분명해집니다:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
이제 Dog와 Cat 모두 Speak 기능을 공유하지만, 각각 고유한 구현을 제공합니다. 두 타입 모두에서 .speak()를 호출할 수 있습니다:
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex가 말합니다: Woof!
println!("{}", cat.speak()); // Whiskers가 말합니다: Meow!
이것이 Rust 다형성의 기초입니다. 서로 다른 타입, 동일한 인터페이스, 고유한 동작들입니다.
챌린지
쉬움서로 다른 타입에 대해 트레이트(trait)를 구현하여 트레이트를 실제로 활용해 봅시다! Describable 트레이트를 만들고 이를 두 개의 서로 다른 구조체에 구현하여, 각 구조체가 자신만의 고유한 설명을 제공하도록 할 것입니다.
코드는 다음 세 개의 파일로 구성됩니다:
describable.rs:describe(&self) -> String메서드를 가진 공개(public)Describable트레이트를 정의합니다.items.rs: 트레이트를 구현하는 두 개의 공개 구조체를 생성합니다:- 공개
title필드(String)를 가진Book - 공개
name필드(String)를 가진Movie
Describable을 구현해야 합니다.- 공개
main.rs: 모듈들을 하나로 모으고, 두 구조체의 인스턴스를 생성한 뒤, 각각의describe메서드를 호출하여 동일한 트레이트가 서로 다른 타입에 대해 어떻게 다른 출력을 생성하는지 보여줍니다.
Book은 자신을 Book: {title}로 설명해야 하며, Movie는 자신을 Film: {name}으로 설명해야 합니다. 각 타입이 동일한 규약을 따르면서도 각자 고유한 동작을 수행하는 방식에 주목하세요!
메인 파일에서 제공된 두 개의 입력을 사용하여 책과 영화를 생성한 다음, 각각의 설명을 별도의 줄에 출력하세요.
출력은 다음 형식을 따라야 합니다:
Book: {title}
Film: {name}예를 들어, 입력값이 1984와 Inception인 경우:
Book: 1984
Film: Inception책 제목과 영화 이름이라는 두 개의 입력을 받게 됩니다.
치트 시트
구조체에 트레이트(trait)를 구현하려면, impl TraitName for StructName 구문을 사용합니다:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
여러 타입이 서로 다른 동작으로 동일한 트레이트를 구현할 수 있습니다:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex says: Woof!
println!("{}", cat.speak()); // Whiskers says: Meow!
이를 통해 Rust에서 다형성(polymorphism)이 가능해집니다. 즉, 서로 다른 타입들이 고유한 구현을 가지면서 동일한 인터페이스를 공유할 수 있습니다.
직접 해보기
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// 입력 읽기
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: 제목을 사용하여 Book 인스턴스 생성
// TODO: 이름을 사용하여 Movie 인스턴스 생성
// TODO: 책의 설명 출력
// TODO: 영화의 설명 출력
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.