Step 01: 트레이트 (Traits) 이해하기
0 studying now
foundations 60 min
트레이트 (Traits) 이해하기
트레이트로 공통 동작을 정의하고 구현합니다.
Execute this step
Run from project root:
cargo runStep 1: 트레이트 (Traits) 이해하기
학습 목표
- 트레이트로 공통 인터페이스 정의하기
- 여러 타입에 트레이트 구현하기
- 트레이트 바운드로 제네릭 제약하기
핵심 개념
1. 트레이트란?
트레이트는 다른 언어의 인터페이스와 유사합니다. 타입이 가져야 할 메서드를 정의합니다.
trait Summary { fn summarize(&self) -> String; }
2. 트레이트 구현
1struct Book { 2 title: String, 3 author: String, 4} 5 6impl Summary for Book { 7 fn summarize(&self) -> String { 8 format!("{} by {}", self.title, self.author) 9 } 10}
3. 기본 구현
1trait Summary { 2 fn summarize(&self) -> String { 3 String::from("(더 읽기...)") 4 } 5} 6 7// 기본 구현 사용 8impl Summary for Book {}
4. 트레이트 바운드
1// 트레이트를 구현한 타입만 받기 2fn notify<T: Summary>(item: &T) { 3 println!("뉴스: {}", item.summarize()); 4} 5 6// 여러 트레이트 7fn process<T: Summary + Display>(item: &T) { 8 // ... 9} 10 11// where 절 (더 읽기 쉬움) 12fn process<T>(item: &T) 13where 14 T: Summary + Display, 15{ 16 // ... 17}
커스텀 트레이트 구현
src/lib.rs에 추가:
1use std::fmt; 2 3// 커스텀 트레이트: 빌릴 수 있는 것 4pub trait Borrowable { 5 fn can_borrow(&self) -> bool; 6 fn borrow_item(&mut self, borrower: String, due_date: String) -> Result<(), String>; 7 fn return_item(&mut self) -> Result<(), String>; 8} 9 10impl Borrowable for Book { 11 fn can_borrow(&self) -> bool { 12 matches!(self.status, BookStatus::Available) 13 } 14 15 fn borrow_item(&mut self, borrower: String, due_date: String) -> Result<(), String> { 16 if self.can_borrow() { 17 self.status = BookStatus::Borrowed { by: borrower, due_date }; 18 Ok(()) 19 } else { 20 Err("대여할 수 없습니다".to_string()) 21 } 22 } 23 24 fn return_item(&mut self) -> Result<(), String> { 25 match self.status { 26 BookStatus::Borrowed { .. } => { 27 self.status = BookStatus::Available; 28 Ok(()) 29 } 30 _ => Err("대여 중이 아닙니다".to_string()), 31 } 32 } 33} 34 35// Display 트레이트 구현 36impl fmt::Display for Book { 37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 38 let status_str = match &self.status { 39 BookStatus::Available => "대여 가능".to_string(), 40 BookStatus::Borrowed { by, due_date } => { 41 format!("대여 중: {} ({})", by, due_date) 42 } 43 BookStatus::Reserved { by } => format!("예약: {}", by), 44 BookStatus::Lost => "분실".to_string(), 45 }; 46 write!(f, "[{}] {} - {} ({})", self.id, self.title, self.author, status_str) 47 } 48} 49 50impl fmt::Display for Category { 51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 52 let name = match self { 53 Category::Fiction => "소설", 54 Category::NonFiction => "비소설", 55 Category::Science => "과학", 56 Category::History => "역사", 57 }; 58 write!(f, "{}", name) 59 } 60}
제네릭 함수에서 트레이트 사용
1// 트레이트 바운드를 사용한 제네릭 함수 2pub fn print_borrowable_status<T: Borrowable + fmt::Display>(item: &T) { 3 println!("{}", item); 4 if item.can_borrow() { 5 println!(" → 대여 가능!"); 6 } else { 7 println!(" → 대여 불가"); 8 } 9} 10 11// 사용 12let book = Book::new(1, "러스트".to_string(), "스티브".to_string(), Category::Science); 13print_borrowable_status(&book);
트레이트 객체 (동적 디스패치)
1// 여러 타입을 하나의 벡터에 저장 2pub struct LibraryItem { 3 pub item: Box<dyn Borrowable>, 4} 5 6// 나중에 DVD, Magazine 등 추가 가능 7pub struct DVD { 8 pub title: String, 9 pub available: bool, 10} 11 12impl Borrowable for DVD { 13 fn can_borrow(&self) -> bool { 14 self.available 15 } 16 // ... 17}
표준 라이브러리 트레이트
From과 Into
1// From 구현하면 Into는 자동으로 구현됨 2impl From<&str> for Category { 3 fn from(s: &str) -> Self { 4 match s.to_lowercase().as_str() { 5 "fiction" | "소설" => Category::Fiction, 6 "nonfiction" | "비소설" => Category::NonFiction, 7 "science" | "과학" => Category::Science, 8 "history" | "역사" => Category::History, 9 _ => Category::NonFiction, 10 } 11 } 12} 13 14// 사용 15let category: Category = "science".into();
실습 코드
1use book_manager::*; 2 3fn main() { 4 println!("=== 트레이트 데모 ===\n"); 5 6 let mut book = Book::new( 7 1, 8 "러스트 프로그래밍".to_string(), 9 "스티브".to_string(), 10 Category::Science, 11 ); 12 13 // Display 트레이트 14 println!("책 정보: {}", book); 15 println!("카테고리: {}", book.category); 16 17 println!(); 18 19 // Borrowable 트레이트 20 if book.can_borrow() { 21 println!("대여 가능합니다."); 22 book.borrow_item("김철수".to_string(), "2026-02-20".to_string()).ok(); 23 println!("대여 후: {}", book); 24 } 25 26 if !book.can_borrow() { 27 println!("현재 대여 불가능합니다."); 28 } 29 30 println!(); 31 32 book.return_item().ok(); 33 println!("반납 후: {}", book); 34 35 println!(); 36 37 // From/Into 트레이트 38 let category: Category = "fiction".into(); 39 println!("변환된 카테고리: {}", category); 40 41 // 제네릭 함수 사용 42 println!("\n=== 대여 가능 여부 확인 ==="); 43 print_borrowable_status(&book); 44}
체크리스트
- [ ] 커스텀 트레이트를 정의했습니다
- [ ] 트레이트를 구조체에 구현했습니다
- [ ] Display 트레이트를 구현했습니다
- [ ] 트레이트 바운드를 사용한 제네릭 함수를 만들었습니다
- [ ] From/Into 트레이트를 이해했습니다
다음 단계
Step 2에서는 async/await를 배우고 비동기 프로그래밍을 시작합니다.