3장: 고급 트레이트

3.1 연관 타입 (Associated Types)

연관 타입은 트레이트 내에서 타입 플레이스홀더를 정의합니다. 제네릭보다 간결하고 사용하기 쉽습니다.

3.1.1 연관 타입 vs 제네릭

// 제네릭 방식 (덜 선호)
trait Container<T> {
    fn add(&mut self, item: T);
}

// 연관 타입 방식 (더 선호)
trait Container {
    type Item;
    fn add(&mut self, item: Self::Item);
}

struct Stack<T> {
    items: Vec<T>,
}

impl<T> Container for Stack<T> {
    type Item = T;

    fn add(&mut self, item: T) {
        self.items.push(item);
    }
}

fn main() {
    let mut stack = Stack { items: vec![] };
    stack.add(42);
    stack.add(100);
}

3.1.2 Iterator 트레이트

// 표준 라이브러리의 Iterator
pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

// 커스텀 이터레이터 구현
struct Counter {
    count: u32,
}

impl Counter {
    fn new() -> Counter {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.count < 5 {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let counter = Counter::new();
    for num in counter {
        println!("{}", num); // 1, 2, 3, 4, 5
    }
}

3.2 트레이트 객체와 동적 디스패치

트레이트 객체를 사용하면 다른 타입의 값을 동일하게 처리할 수 있습니다.

3.2.1 정적 vs 동적 디스패치

trait Draw {
    fn draw(&self);
}

struct Circle {
    radius: f64,
}

struct Rectangle {
    width: f64,
    height: f64,
}

impl Draw for Circle {
    fn draw(&self) {
        println!("Drawing circle with radius {}", self.radius);
    }
}

impl Draw for Rectangle {
    fn draw(&self) {
        println!("Drawing rectangle {}x{}", self.width, self.height);
    }
}

// 정적 디스패치 (컴파일 타임, 더 빠름)
fn draw_static<T: Draw>(shape: &T) {
    shape.draw();
}

// 동적 디스패치 (런타임, 더 유연함)
fn draw_dynamic(shape: &dyn Draw) {
    shape.draw();
}

fn main() {
    let circle = Circle { radius: 5.0 };
    let rect = Rectangle { width: 10.0, height: 20.0 };

    draw_static(&circle);
    draw_static(&rect);

    draw_dynamic(&circle);
    draw_dynamic(&rect);

    // 트레이트 객체 벡터
    let shapes: Vec<Box<dyn Draw>> = vec![
        Box::new(Circle { radius: 3.0 }),
        Box::new(Rectangle { width: 5.0, height: 7.0 }),
    ];

    for shape in shapes.iter() {
        shape.draw();
    }
}

3.2.2 객체 안전성 (Object Safety)

// 객체 안전한 트레이트
trait Animal {
    fn make_sound(&self);
}

// 객체 안전하지 않은 트레이트
trait Cloneable {
    fn clone(&self) -> Self; // Self 반환 = 객체 안전하지 않음
}

// 수정된 객체 안전한 버전
trait CloneBox {
    fn clone_box(&self) -> Box<dyn CloneBox>;
}

impl<T: Clone + 'static> CloneBox for T {
    fn clone_box(&self) -> Box<dyn CloneBox> {
        Box::new(self.clone())
    }
}

3.3 고급 트레이트 바운드

3.3.1 where 절

use std::fmt::Display;

// 복잡한 제네릭 함수
fn complex_function<T, U>(t: &T, u: &U) -> i32
where
    T: Display + Clone,
    U: Clone + Debug,
{
    println!("t: {}", t);
    println!("u: {:?}", u);
    42
}

// 연관 타입 바운드
fn print_items<C>(container: C)
where
    C: Iterator,
    C::Item: Display,
{
    for item in container {
        println!("{}", item);
    }
}

3.3.2 슈퍼트레이트 (Supertraits)

use std::fmt;

// Display를 구현하려면 반드시 Debug도 구현해야 함
trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

struct Point {
    x: i32,
    y: i32,
}

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl OutlinePrint for Point {}

fn main() {
    let p = Point { x: 1, y: 3 };
    p.outline_print();
}

3.4 디폴트 제네릭 타입 매개변수

use std::ops::Add;

#[derive(Debug, Copy, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

// Add 트레이트의 디폴트 타입 매개변수
impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

// 다른 타입과의 덧셈
struct Millimeters(u32);
struct Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}

fn main() {
    assert_eq!(
        Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
        Point { x: 3, y: 3 }
    );

    let mm = Millimeters(1000);
    let m = Meters(1);
    let total = mm + m;
    println!("{}mm", total.0);
}

3.5 완전 정규화 구문 (Fully Qualified Syntax)

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.");
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("Up!");
    }
}

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*");
    }
}

fn main() {
    let person = Human;

    person.fly(); // Human::fly 호출

    // 명시적으로 호출
    Pilot::fly(&person);
    Wizard::fly(&person);
    Human::fly(&person);

    // 연관 함수의 경우
    trait Animal {
        fn baby_name() -> String;
    }

    struct Dog;

    impl Dog {
        fn baby_name() -> String {
            String::from("Spot")
        }
    }

    impl Animal for Dog {
        fn baby_name() -> String {
            String::from("puppy")
        }
    }

    println!("A baby dog is called a {}", Dog::baby_name());
    // 완전 정규화 구문
    println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}

3.6 실전 예제: 플러그인 시스템

use std::collections::HashMap;

// 플러그인 트레이트
trait Plugin: Send + Sync {
    fn name(&self) -> &str;
    fn execute(&self, args: &[&str]) -> Result<String, String>;
    fn help(&self) -> &str;
}

// 구체적인 플러그인들
struct EchoPlugin;

impl Plugin for EchoPlugin {
    fn name(&self) -> &str {
        "echo"
    }

    fn execute(&self, args: &[&str]) -> Result<String, String> {
        Ok(args.join(" "))
    }

    fn help(&self) -> &str {
        "Echo back the input arguments"
    }
}

struct UpperPlugin;

impl Plugin for UpperPlugin {
    fn name(&self) -> &str {
        "upper"
    }

    fn execute(&self, args: &[&str]) -> Result<String, String> {
        Ok(args.join(" ").to_uppercase())
    }

    fn help(&self) -> &str {
        "Convert input to uppercase"
    }
}

// 플러그인 매니저
struct PluginManager {
    plugins: HashMap<String, Box<dyn Plugin>>,
}

impl PluginManager {
    fn new() -> Self {
        PluginManager {
            plugins: HashMap::new(),
        }
    }

    fn register(&mut self, plugin: Box<dyn Plugin>) {
        let name = plugin.name().to_string();
        self.plugins.insert(name, plugin);
    }

    fn execute(&self, name: &str, args: &[&str]) -> Result<String, String> {
        self.plugins
            .get(name)
            .ok_or_else(|| format!("Plugin '{}' not found", name))?
            .execute(args)
    }

    fn list_plugins(&self) {
        println!("Available plugins:");
        for (name, plugin) in &self.plugins {
            println!("  {}: {}", name, plugin.help());
        }
    }
}

fn main() {
    let mut manager = PluginManager::new();

    manager.register(Box::new(EchoPlugin));
    manager.register(Box::new(UpperPlugin));

    manager.list_plugins();

    match manager.execute("echo", &["Hello", "World"]) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
    }

    match manager.execute("upper", &["hello", "rust"]) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
    }
}
🎯 핵심 요약: