이번 편의 목표: 종이책과 전자책이 서로 다른 하루 요율을 쓰면서, 같은 fee 이름으로 호출되게 합니다.

trait는 타입이 갖춰야 하는 메서드 목록입니다. impl 트레이트 for 타입으로 그 목록을 구현합니다. 인자가 &impl Overdue이면, Overdue를 구현한 어떤 타입이든 빌릴 수 있습니다. 호출부는 fee만 알면 됩니다.

Rust
trait Overdue {
    fn fee(&self) -> i32;
}

struct Paper {
    days: i32,
}

struct Ebook {
    days: i32,
}

impl Overdue for Paper {
    fn fee(&self) -> i32 {
        if self.days <= 0 { 0 } else { self.days * 100 }
    }
}

impl Overdue for Ebook {
    fn fee(&self) -> i32 {
        if self.days <= 0 { 0 } else { self.days * 50 }
    }
}

fn print_fee(item: &impl Overdue) {
    println!("{}", item.fee());
}

fn main() {
    print_fee(&Paper { days: 2 });
    print_fee(&Ebook { days: 2 });
}

출력은 200과 100, 두 줄입니다. 종이책은 하루 100원, 전자책은 하루 50원입니다. print_fee는 구조체 필드를 모릅니다. 트레이트가 공개한 fee만 호출합니다. 두 호출의 구체 타입은 다르지만, 각각 Overdue를 구현했기 때문에 같은 함수에 들어갑니다.

한 벡터에 종이책과 전자책을 섞어 담으려면 구체 타입 대신 트레이트 객체가 필요합니다. 이 연재의 20편은 한 종류의 대출 기록만 다루므로, 섞는 목록은 범위 밖에 둡니다.

직접 해 보기

두 구조체의 days를 3으로 바꿔 출력이 300과 150인지 확인하세요.

해설

종이책 3일은 300원이고 전자책 3일은 150원입니다. print_fee는 수정하지 않습니다.