Skip to content

Files

Latest commit

af97933 ยท Mar 5, 2025

History

History
1485 lines (1201 loc) ยท 64.8 KB

04_trait.md

File metadata and controls

1485 lines (1201 loc) ยท 64.8 KB

ํŠธ๋ ˆ์ดํŠธ(Trait) ์†Œ๊ฐœ

ํŠธ๋ ˆ์ดํŠธ๋Š” ์–ด๋–ค ํƒ€์ž…์ด๋“  ์ƒ๊ด€์—†์ด ๊ณตํ†ต๋œ ๋™์ž‘์„ ํ•˜๋„๋ก ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๊ฐ์ฒด๋“ค์ด๋ผ๊ณ  ํ•ด๋„ ๊ฐ™์€ ํŠธ๋ ˆ์ดํŠธ์„ ๊ตฌํ˜„ํ•˜๋„๋ก ๋งŒ๋“ค๋ฉด ๊ฒฐ๊ตญ ๊ณตํ†ต๋œ ํŠน์ง•์„ ๊ฐ–๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ธ์ž๋กœ ๊ฐ์ฒด๋ฅผ ๋„˜๊ธธ ๋•Œ, ํƒ€์ž…์„ ์ง€์ •ํ•˜๋Š”๊ฒŒ ๋ณดํ†ต์ด์ง€๋งŒ, ํŠน์ •ํ•œ ํŠธ๋ ˆ์ดํŠธ์„ ๊ตฌํ˜„ํ•œ ํƒ€์ž…์ด๋ฉด ๋ฌด์—‡์ด๋“ ์ง€ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ธ์ž์— ๊ตฌ์กฐ์ฒด ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ, ์–ด๋–ค ํŠธ๋ ˆ์ดํŠธ์˜ ์ด๋ฆ„์„ ์“ธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด๋ฅผ ๊ฒฝํ—˜ํ•ด๋ดค๋‹ค๋ฉด ์ถ”์ƒ ํด๋ž˜์Šค๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋น„์Šทํ•œ ๊ฒƒ์ด๋ผ๊ณ  ์ดํ•ดํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ๊ฐ์ฒด๋“ค์„ ๋ฌถ๋Š” ์ถ”์ƒํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ธฐ๋„ ํ•˜๊ณ , ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋Š” ๋“ฑ ๋Ÿฌ์ŠคํŠธ๋กœ ๊ทœ๋ชจ์žˆ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•„์ˆ˜์ ์œผ๋กœ ์ž˜ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ๋˜๋Š” ๋ฌธ๋ฒ•์ž…๋‹ˆ๋‹ค.

์•„์ฃผ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ตฌ์กฐ์ฒด Person๊ณผ Book์— ๊ณตํ†ต์˜ ํŠธ๋ ˆ์ดํŠธ Printable์„ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

// src/trait/main.rs
trait Printable {
    type Age;
    fn print(&self);
    fn get_age(&self) -> Self::Age;
}

struct Person {
    name: String,
    age: u32,
}

impl Person {
    fn new(name: &str, age: u32) -> Self {
        Person {
            name: name.to_string(),
            age: age,
        }
    }
}

impl Printable for Person {
    type Age = u32;
    fn print(&self) {
        println!("Name: {}, {} years old", self.name, self.get_age());
    }
    fn get_age(&self) -> Self::Age {
        self.age
    }
}

struct Book {
    title: String,
    author: String,
    published: u32,
}

impl Printable for Book {
    type Age = u32;
    fn print(&self) {
        println!(
            "Title: {}\nAuthor: {}\nPublished: {}",
            self.title,
            self.author,
            self.get_age()
        );
    }
    fn get_age(&self) -> Self::Age {
        self.published
    }
}

fn print_info(item: &dyn Printable<Age = u32>) {
    item.print();
}

fn main() {
    let person = Person::new("Alice", 22);
    let book = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
    };

    print_info(&person);
    print_info(&book);
}
$ cargo run --bin trait
    Finished dev [unoptimized + debuginfo] target(s) in 0.75s
     Running `target/debug/trait`
Name: Alice, 22 years old
Title: The Rust Programming Language
Author: Steve Klabnik and Carol Nichols
Published: 20230228

์ฒซ๋ฒˆ์งธ๋กœ Printable์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์„ ์–ธํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค.

trait Printable {
    type Age;
    fn print(&self);
    fn get_age(&self) -> Self::Age;
}

Printable์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ์—๋Š” 2๊ฐœ์˜ ํ•จ์ˆ˜์™€ 1๊ฐœ์˜ ํƒ€์ž…์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด์ œ ์ด ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ๊ตฌ์กฐ์ฒด๋“ค์€ 2๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Age๋ผ๋Š” ํƒ€์ž…์„ ๋ฌด์Šจ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ •ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. i32๊ฐ™์€ ๊ธฐ๋ณธ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„์žˆ๊ณ , ์ƒˆ๋กœ์šด ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ํŠธ๋ ˆ์ดํŠธ๋ผ๋Š” ๊ฒƒ์ด ๋ฐ˜๋“œ์‹œ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ๋งŒ์ด ์•„๋‹ˆ๋ผ, ์–ด๋–ค ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์“ธ์ง€๋„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ฃผ์˜ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Person ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

struct Person {
    name: String,
    age: u32,
}

impl Person {
    fn new(name: &str, age: u32) -> Self {
        Person {
            name: name.to_string(),
            age: age,
        }
    }
}

์šฐ์„  Personํƒ€์ž…์ด ํŠธ๋ ˆ์ดํŠธ์™€ ์ƒ๊ด€์—†์ด ๊ฐ€์ง€๋Š” Personํƒ€์ž…๋งŒ์˜ ๊ณ ์œ ํ•œ ํ•จ์ˆ˜ new๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ์œผ๋กœ Person์„ ์œ„ํ•ด Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

impl Printable for Person {
    type Age = u32;
    fn print(&self) {
        println!("Name: {}, {} years old", self.name, self.get_age());
    }
    fn get_age(&self) -> Self::Age {
        self.age
    }
}

์‚ฌ๋žŒ์˜ ๋‚˜์ด๋ฅผ ์˜๋ฏธํ•˜๋Š” Age๋ผ๋Š” ํƒ€์ž…์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž… ์ด๋ฆ„์€ Age์ด์ง€๋งŒ, ์‚ฌ์‹ค์€ u32ํƒ€์ž…์˜ ๋ณ„์นญ(alias)์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ ๋‚˜์ด๋Š” ์Œ์ˆ˜๊ฐ€ ์—†์œผ๋‹ˆ๊นŒ u32๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  print ํ•จ์ˆ˜์™€ get_ageํ•จ์ˆ˜์˜ ๊ตฌํ˜„์ด ์žˆ์Šต๋‹ˆ๋‹ค. printํ•จ์ˆ˜๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ํ„ฐ๋ฏธ๋„์— ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. get_ageํ•จ์ˆ˜๋Š” Ageํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•ด์•ผํ•˜๋‹ˆ๊นŒ ๊ฒฐ๊ณผ์ ์œผ๋กœ๋Š” u32ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Book ๊ตฌ์กฐ์ฒด์˜ ์ •์˜์™€, Book ๊ตฌ์กฐ์ฒด๋ฅผ ์œ„ํ•œ Printable ํŠธ๋ ˆ์ดํŠธ์˜ ๊ตฌํ˜„์ด ๋‚˜์˜ต๋‹ˆ๋‹ค.

struct Book {
    title: String,
    author: String,
    published: u32,
}

impl Printable for Book {
    type Age = u32;
    fn print(&self) {
        println!(
            "Title: {}\nAuthor: {}\nPublished: {}",
            self.title, self.author, self.get_age()
        );
    }
    fn get_age(&self) -> Self::Age {
        self.published
    }
}

Ageํƒ€์ž…์„ u32๋กœ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  printํ•จ์ˆ˜์™€ get_ageํ•จ์ˆ˜์˜ ๊ตฌํ˜„์ด ๋‚˜์˜ต๋‹ˆ๋‹ค. print๋Š” ์ฑ…์˜ ์ œ๋ชฉ๊ณผ ์ €์ž, ์ถœํŒ๋‚ ์งœ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ์„ ์œ„ํ•œ Printable ํŠธ๋ ˆ์ดํŠธ์™€ ์ฑ…์„ ์œ„ํ•œ ํŠธ๋ ˆ์ดํŠธ๋Š” ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ๋‚ด๋ถ€ ๋™์ž‘๋งŒ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์ด์ œ ์ •๋ง ์ค‘์š”ํ•œ๊ฒŒ ๋‚˜์˜ต๋‹ˆ๋‹ค. ๋ฐ”๋กœ dyn์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์“ฐ๋Š” ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

fn print_info(item: &dyn Printable<Age = u32>) {
    item.print();
}

print_info๋ผ๋Š” ํ•จ์ˆ˜์ธ๋ฐ, ์ธ์ž์˜ ํƒ€์ž…์ด ํŠน์ดํ•ฉ๋‹ˆ๋‹ค. dyn์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๋Š” ์ฐธ์กฐ ํƒ€์ž…์ž…๋‹ˆ๋‹ค. โ€œdyn Printableโ€๋Š” Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ๋ชจ๋“  ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์ฐธ์กฐ ํ‚ค์›Œ๋“œ &๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ํƒ€์ž…์˜ ์ฐธ์กฐ๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค๋Š” ๋œป์ด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ฃผ์˜ํ•  ๊ฒƒ์ด ํ•˜๋‚˜์žˆ๋Š”๋ฐ <Age=u32>๋ผ๋Š” ๊ตฌ๋ฌธ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์˜ ์˜๋ฏธ๋Š” Ageํƒ€์ž…์„ u32๋กœ ์ •์˜ํ•œ ๊ฐ์ฒด๋งŒ ์ฐธ์กฐํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด ๋ฉ๋‹ˆ๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋˜ Ageํƒ€์ž…์„ u32๋กœ ์ •์˜ํ•œ ํƒ€์ž…๋“ค์˜ ์ฐธ์กฐ๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. print_infoํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž… Person๊ณผ Book์˜ ์ฐธ์กฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ๋˜๋Š” ์ด์œ ๊ฐ€ ๋ฐ”๋กœ, Person๊ณผ Book์ด Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ–ˆ๊ณ , Ageํƒ€์ž…์„ u32๋กœ ์ •์˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹คํ•ด๋„, Age์˜ ํƒ€์ž…์ด u32์ด ์•„๋‹Œ ๋‹ค๋ฅธ ํƒ€์ž…์ด์—ˆ๋‹ค๋ฉด print_infoํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๋ชจ๋‘ ๋‹ค ๊ตฌํ˜„ํ•˜๋Š” ํƒ€์ž…๋“ค์„ ์ง€์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

fn some_function(param: &(dyn Trait1 + Trait2)) {
    // Function body
}

Trait1๊ณผ Trait2๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•œ ํƒ€์ž…์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ด์™€๊ฐ™์ด dyn ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํŠธ๋ ˆ์ดํŠธ ์ด๋ฆ„์œผ๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์„ ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ํŠน์ •ํ•œ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋“ค์„ ์ง€์ •ํ•œ๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋ ๋“ฏํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ด€ ํƒ€์ž…(Associated Type)๊ณผ ์—ฐ๊ด€ ํ•จ์ˆ˜ (Associated Function)

์ด์ „ ์˜ˆ์ œ์—์„œ Printable ํŠธ๋ ˆ์ดํŠธ์— ์žˆ๋Š” Age ํƒ€์ž…์„ ์—ฐ๊ด€ ํƒ€์ž…์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์— ๊ณตํ†ต์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ ์–ด๋–ค ํƒ€์ž…์ด ๋ ์ง€๋Š” ๊ตฌํ˜„์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. print_info ํ•จ์ˆ˜์—์„œ์™€ ์—ฐ๊ด€ ํƒ€์ž…์„ ๋™์ผํ•˜๊ฒŒ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋“ค์„ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Person๊ตฌ์กฐ์ฒด์— ์žˆ๋Š” new ํ•จ์ˆ˜๋ฅผ ์—ฐ๊ด€ ํ•จ์ˆ˜๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์ž์„ธํžˆ๋ณด๋ฉด ํ•จ์ˆ˜์˜ ์ธ์ž์— self๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํŠน์ • ๊ตฌ์กฐ์ฒด ๊ฐ์ฒด์— ์ข…์†๋˜์„œ ๋™์ž‘ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๊ฐ์ฒด๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ Person::new์™€ ๊ฐ™์ด Person์ด๋ผ๋Š” ํƒ€์ž… ์ด๋ฆ„์œผ๋กœ๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต new๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์—ฐ๊ด€ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š”๊ฒŒ ๊ด€๋ก€์ž…๋‹ˆ๋‹ค.

ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด(Trait object)

dynํ‚ค์›Œ๋“œ๋Š” ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‚ค์›Œ๋“œ์ž…๋‹ˆ๋‹ค. ์ด ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋ฅผ ์ข€๋” ์ž์„ธํžˆ ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

dyn TraitName

์œ„์—์„œ๋ณธ print_infoํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. print_infoํ•จ์ˆ˜๋Š” item์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด์˜ printํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž… ์ด๋ฆ„์ด ์—†๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

fn print_info(item: &dyn Printable<Age = u32>) {
    item.print();
}

Personํƒ€์ž…์˜ printํ•จ์ˆ˜๋Š” 0x1000_0000์— ์žˆ๊ณ , Bookํƒ€์ž…์˜ printํ•จ์ˆ˜๋Š” 0x3000_0000์— ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” vtable์ด๋ผ๋Š” ๊ฒƒ์„ ๋งŒ๋“ค์–ด์„œ ํŠธ๋ ˆ์ดํŠธ์—์„œ ๊ตฌํ˜„๋œ ํ•จ์ˆ˜๋“ค์˜ ํฌ์ธํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. (์ด๊ฒƒ์€ ์ž๋ฐ”๋‚˜ C++์˜ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.)

book.vtable = {
    print = 0x1000_0000;
    ... ๋‹ค๋ฅธ ํ•จ์ˆ˜๋“ค์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋“ค๋„ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ
}
person.vtable = {
    print = 0x3000_0000;
    ... ๋‹ค๋ฅธ ํ•จ์ˆ˜๋“ค์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋“ค๋„ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ
}

fn print_info(item: &dyn Printable<Age = u32>) {
    item.vtable.print()
}

์œ„์™€๊ฐ™์ด ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฐ์ฒด๋งˆ๋‹ค vtable์„ ์ถ”๊ฐ€ํ•ด์„œ ํŠธ๋ ˆ์ดํŠธ ํ•จ์ˆ˜๋“ค์˜ ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ถ”๊ฐ€์ ์ธ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์„œ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์ €์ •ํ•˜๊ณ , ์š”์ฒญ๋ฐ›์€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์„ Dynamic dispatch๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค๋งŒ ์šฉ์–ด๋ณด๋‹ค๋Š” ๊ณตํ†ต๋œ ํŠน์„ฑ ํ˜น์€ ํ•จ์ˆ˜๋“ค์˜ ๊ตฌํ˜„์„ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ ์žˆ๋Š”๊ฒŒ ์ค‘์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•œ๋ฒˆ ๋” ์ฝ๊ฒŒ๋˜๋Š” ๋‹จ์ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค๋งŒ ํŠน๋ณ„ํ•˜๊ฒŒ CPU๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”ํ•œ ์„ฑ๋Šฅ์— ์ฐจ์ด๊ฐ€ ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋œ ํŠธ๋ ˆ์ดํŠธ

๊ฐœ๋ฐœ์ž๋“ค์ด ์ง์ ‘ ํ•„์š”ํ•œ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, ๋Ÿฌ์ŠคํŠธ์˜ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(The Rust Standard Library: https://doc.rust-lang.org/std/index.html)์—์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“ค๋†“์€ ํŽธ๋ฆฌํ•œ ํŠธ๋ ˆ์ดํŠธ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๋งŒํผ ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„๋งŒํผ ์„ฑ๋Šฅ์ด๋‚˜ ๋ฒ”์šฉ์ ์ด ์ข‹์€ ํŠธ๋ ˆ์ดํŠธ๋“ค์ž…๋‹ˆ๋‹ค. ๊ทธ์ค‘์—์„œ ์ดˆ๋ณด ๋‹จ๊ณ„์—์„œ๋„ ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ฒŒ๋˜๋Š” ๋ช‡๊ฐ€์ง€๋งŒ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ std::fmt::{Display, Debug}

๊ฐ์ฒด๋ฅผ ํ„ฐ๋ฏธ๋„์— ์ถœ๋ ฅํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ด์•ผ๊ธฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๋””๋ฒ„๊น…ํ•  ๋•Œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ธํ„ฐ๋ ‰ํ‹ฐ๋ธŒํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋‹ค๋ณด๋ฉด ๊ฐ์ฒด์˜ ๊ฐ’์„ ํ„ฐ๋ฏธ๋„์— ์ถœ๋ ฅํ•ด์•ผ๋  ์ผ์ด ์ž์ฃผ ์ƒ๊น๋‹ˆ๋‹ค.

๊ฐ์ฒด๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ์œ„ํ•ด์„œ ์ด๋ฏธ ์šฐ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ๋ฒˆ ์‚ฌ์šฉํ•ด๋ณธ๊ฒŒ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ฒด์— derive(Debug)๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•ด์„œ ๋””๋ฒ„๊ทธ ๋ฉ”์„ธ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š”๊ฑธ ํ•ด๋ดค์—ˆ์Šต๋‹ˆ๋‹ค.

#[derive(Debug)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

fn main() {
    let dot: Point = Point { x: 1.2, y: 3.4 };
    println!("{:?}", dot);
}

derive๋ผ๋Š” ๊ตฌ๋ฌธ์€ ์‚ฌ์ „์ ์œผ๋กœ๋Š” ์œ ๋ž˜ํ•˜๋‹ค, ํŒŒ์ƒํ•˜๋‹ค๋ผ๋Š” ๋œป์„ ๊ฐ€์ง€๊ณ ์žˆ๋Š”๋ฐ Point๋ผ๋Š” ๊ตฌ์กฐ์ฒด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด๋‹ฌ๋ผ๋Š” ์˜๋ฏธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์ง€์•Š๊ณ  ๋‚ด๊ฐ€ ์ง์ ‘ ๋งŒ๋“ค์–ด์„œ ์“ธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ด์ „์— trait์˜ ๊ตฌํ˜„์ฒด๋ฅผ ๋งŒ๋“ค์–ด๋ณธ๊ฒƒ ์ฒ˜๋Ÿผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋‹จ std::fmt::Debug๋ผ๋Š” trait๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•ˆ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„์„ ์‹œ์ž‘ํ•  ์ˆ˜๋Š” ์žˆ๊ฒ ๋Š”๋ฐ, ์ด ํŠธ๋ ˆ์ดํŠธ์˜ ์–ด๋А ๋ฉ”์†Œ๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š”์ง€๋ฅผ ์–ด๋””์—์„œ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์„๊นŒ์š”?

impl fmt::Debug for Point {

}

์•„๋ž˜ Debug ํŠธ๋ ˆ์ดํŠธ์˜ ๋ฉ”๋‰ด์–ผ์„ ํ™•์ธํ•˜๋ฉด ์–ด๋А ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๊ณ , ์–ด๋–ค ์—ญํ• ์„ ๊ฐ€์ง€๋Š”์ง€๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://doc.rust-lang.org/std/fmt/trait.Debug.html

๊ฐ€์žฅ ์œ—๋ถ€๋ถ„์„ ๋ณด๋ฉด ํŠธ๋ ˆ์ดํŠธ์˜ ์ •์˜์™€ ํ•„์ˆ˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

pub trait Debug {
    // Required method
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>;
}

โ€œRequired methodโ€๋ผ๊ณ  ์จ๋†“์€ ๊ฒƒ์„ ๋ณด๋‹ˆ fmt๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋˜๊ฒ ๋„ค์š”. ๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์‹ค ๊ตฌํ˜„์„ ๋ง‰์ƒ ํ•˜๋ ค๊ณ ํ•ด๋„ f๋ผ๋Š” ์ธ์ž๋ฅผ ์–ด๋–ป๊ฒŒ ์จ์•ผํ• ์ง€ ์ •์˜๋งŒ ๋ด์„œ๋Š” ๋ชจ๋ฅผ ์ˆ˜๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. ๋งค๋‰ด์–ผ์„ ์ข€๋” ์ฝ์–ด๋ณด๋ฉด ๋‹ต์ด ๋‚˜์˜ต๋‹ˆ๋‹ค.

impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Point [{} {}]", self.x, self.y)
    }
}

์ด๋Ÿฐ ํ˜•ํƒœ๋กœ ์–ผ๋งˆ๋“ ์ง€ ์ž์œ ๋กญ๊ฒŒ ๊ตฌํ˜„๋งŒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. fmt::Formatter๋ผ๋Š” ๊ฐ์ฒด์— ๋‚ด๊ฐ€ ์ง€์ •ํ•œ ๋ฉ”์„ธ์ง€๋ฅผ ์จ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‹จ์ง€ ์ฃผ์˜ํ•  ๊ฒƒ์€ write!๋งคํฌ๋กœ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ์—์„œ ์ค„์˜ ๋งˆ์ง€๋ง‰์— โ€œ;โ€ ์„ธ๋ฏธ์ฝœ๋ก ์„ ์“ฐ์ง€ ์•Š๋Š” ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. fmtํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ด fmt::Result์ž…๋‹ˆ๋‹ค. write! ๋งคํฌ๋กœ ํ•จ์ˆ˜๊ฐ€ fmt::Result ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ โ€œ;โ€ ์„ธ๋ฏธ์ฝœ๋ก ์„ ์“ฐ๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ";"๋ฅผ ์“ฐ๊ฒŒ๋˜๋ฉด ์•„๋ฌด๋Ÿฐ ๊ฐ’๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ฒŒ๋˜์„œ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด์ œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€๊ฐ™์ด ์šฐ๋ฆฌ๊ฐ€ ์ง€์ •ํ•œ ํ˜•ํƒœ๋กœ ๊ฐ์ฒด์˜ ๊ฐ’์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

// src/trait_display_debug/main.rs
use std::fmt;

pub struct Point {
    pub x: f64,
    pub y: f64,
}

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

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

fn main() {
    let dot: Point = Point { x: 1.2, y: 3.4 };
    println!("{:?}", dot);
    println!("For your information: {}", dot);
}
$ cargo run --bin trait_display_debug
   Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
     Running `target/debug/trait_display_debug`
POINT [1.2 3.4]
For your information: POINT(1.2 3.4)

๊ทธ๋Ÿฐ๋ฐ ๋””๋ฒ„๊น… ์šฉ๋„์™ธ์—๋„ ์‚ฌ์šฉ์ž์—๊ฒŒ ํŠน์ • ๊ตฌ์กฐ์ฒด์˜ ๊ฐ’๋“ค์„ ๋ณด์—ฌ์ค„ ํ•„์š”๊ฐ€ ์žˆ์„๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ๋‚ด๊ฐ€ ๋งŒ๋“  ๋ฐ์ดํ„ฐ ๊ฐ์ฒด์˜ ๊ฐ’์„ ํ™•์ธํ•˜๊ธฐ์œ„ํ•ด ๋””๋ฒ„๊น… ์šฉ๋„๋กœ ์ถœ๋ ฅํ•  ๋•Œ๋„ ์žˆ๊ฒ ์ง€๋งŒ, ๋‚ด๊ฐ€ ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์ ธ๋‹ค์“ธ ๋•Œ, ๊ฐ์ฒด์˜ ๊ฐ’์„ ์ถœ๋ ฅํ•ด๋ณผ ์ˆ˜๋„ ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ์„ ๊ฒฝํ—˜ํ•ด๋ณด์‹  ๋ถ„๋“ค์€ __repr__์ด๋‚˜ __str__๋ฉ”์†Œ๋“œ๊ณผ ์œ ์‚ฌํ•œ ๊ฒƒ๋“ค์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ์ดํ•ดํ•˜๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‚ด๊ฐ€ Point๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ขŒํ‘œ์ƒ์˜ ์ ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด, ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์‚ฌ์šฉ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค.

fn main() {
    let first_dot: Point = get_user();
    let second_dot: Point = get_user();
    println!("The distance between {} and {} is {}", 
              first_dot, second_dot, get_distance(first_dot, second_dot));
}

์‚ฌ์šฉ์ž๊ฐ€ ์ถœ๋ ฅํ•˜๋ ค๋Š” ๋ฉ”์„ธ์ง€๋Š” ๋””๋ฒ„๊น… ๋ฉ”์„ธ์ง€๊ฐ€ ์•„๋‹Œ ์ •์‹์œผ๋กœ ํ„ฐ๋ฏธ๋„์˜ stdout์— ์ถœ๋ ฅํ•˜๋ ค๋Š” ๋ฉ”์„ธ์ง€์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด์„œ Debug ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์•„๋‹Œ std::fmt::Display ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์‹ค ๋‚ด๋ถ€ ๊ตฌํ˜„์€ Debug ์™€ ์™„์ „ํžˆ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ง€ println!๋“ฑ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ถœ๋ ฅ ํ˜•ํƒœ๊ฐ€ {:?}๊ฐ€ ์•„๋‹ˆ๋ผ {}๋ผ๋Š” ์ฐจ์ด ๋ฟ์ž…๋‹ˆ๋‹ค.

Debug์™€ Display๋Š” ์‚ฌ์‹ค์ƒ ๋™์ผํ•œ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค๋งŒ, ์‚ฌ์šฉํ•˜๋Š” ์˜๋„๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํŠน์ • ํƒ€์ž…์„ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ฃผ๊ณ ์žํ•  ๋•Œ๋Š” Display๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์ด๋‚˜ ๊ฐ์ฒด๋“ค๊ฐ„์˜ ํ†ต์‹  ์ธํ„ฐํŽ˜์ด์Šค๋กœ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž„์‹œ๋กœ ๋””๋ฒ„๊น… ์šฉ๋„๋กœ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ ์žํ•  ๋•Œ๋‚˜ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€ ๋“ฑ์—์„œ๋Š” Debug๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์˜๋„์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜๋„์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋‚˜ ๋ฏธ๋ž˜์˜ ๋‚˜ ์ž์‹ ์—๊ฒŒ ๋” ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” Clone

Clone ํŠธ๋ ˆ์ดํŠธ๋Š” clone์ด๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ, ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด ๋ฐ”๋กœ deep copy๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ์€ Clone ํŠธ๋ ˆ์ดํŠธ์˜ ์ •์˜๋ฅผ ๋งค๋‰ด์–ผ์—์„œ ๊ฐ€์ ธ์˜จ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

pub trait Clone: Sized {
    // Required method
    fn clone(&self) -> Self;

    // Provided method
    fn clone_from(&mut self, source: &Self) { ... }
}

ํ•œ๊ฐ€์ง€ ๋จผ์ € ์•Œ์•„์•ผ๋˜๋Š”๊ฒŒ ์žˆ์Šต๋‹ˆ๋‹ค. self์™€ Self์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. self๋Š” ๊ฐ์ฒด ์ž์‹ ์„ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Self๋Š” ๊ฐ์ฒด์˜ ํƒ€์ž…์ž…๋‹ˆ๋‹ค. Self๋Š” ์•„๋ฌด๋Ÿฐ ๊ฐ์ฒด์™€ ์ƒ๊ด€์—†์€ ๋‹จ์ง€ ํ˜„์žฌ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํƒ€์ž…์„ ๊ฐ€๋ฅดํ‚ต๋‹ˆ๋‹ค. ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ตฌ์กฐ์ฒด์ด๋ฉด ๊ตฌ์กฐ์ฒด์˜ ์ด๋ฆ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ cloneํ•จ์ˆ˜๋Š” ์ž๊ธฐ ์ž์‹ ์„ ์ฐธ์กฐํ•˜๋ฉด์„œ, ๊ฐ™์€ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// src/trait_clone/main.rs
#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

impl Clone for Book {
    fn clone(&self) -> Self {
        Book {
            title: self.title.clone(),
            author: self.author.clone(),
            published: self.published,
        }
    }
}

//fn print_info(item: &dyn Clone) {
//    println!("item implements Clone trait");
//}

fn main() {
    let book = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
    };

    let another = Book {
        title: String::from("The another book"),
        author: String::from("Unknown"),
        published: 20111111,
    };

    let mut book_clone = book.clone();
    println!("{:?}", book_clone);
    book_clone.clone_from(&another);
    println!("{:?}", book_clone);

    //print_info(&book);
}
$ cargo run --bin trait_clone
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s
     Running `target/debug/trait_clone`
Book { title: "The Rust Programming Language", author: "Steve Klabnik and Carol Nichols", published: 20230228 }
Book { title: "The another book", author: "Unknown", published: 20111111 }

cloneํ•จ์ˆ˜์˜ ๋‚ด์šฉ์„ ๋ณด๋ฉด ์ƒˆ๋กœ์šด Book ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. titleํ•„๋“œ๋Š” self.title์„ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. self.title์€ Stringํƒ€์ž…์˜ ๊ฐ์ฒด์ด๋ฏ€๋กœ Stringํƒ€์ž…์˜ clone๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋˜‘๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. String ํƒ€์ž…์˜ clone ๋ฉ”์†Œ๋“œ ๋˜ํ•œ Clone ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๊ฒ ์ง€์š”. ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ •์˜๋œ ํƒ€์ž…๋“ค์€ ๋Œ€๋ถ€๋ถ„ clone ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ clone๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€์•Š๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“ ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ๋ ๊นŒ์š”?

impl Clone for Book {
    fn clone(&self) -> Self {
        Book {
            title: self.title,
            author: self.author,
            published: self.published,
        }
    }
}

์†Œ์œ ๊ถŒ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•  ๋•Œ ์ด์•ผ๊ธฐํ•œ ๋ฐ”์™€ ๊ฐ™์ด ํž™ ์˜์—ญ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ ๊ฐ์ฒด๋“ค์€ ์ด์™€๊ฐ™์ด ๋Œ€์ž…์ด ๋ ๋•Œ ์†Œ์œ ๊ถŒ์˜ ์ด๋™์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

error[E0507]: cannot move out of `self.title` which is behind a shared reference
  --> src/main.rs:43:20
   |
43 |             title: self.title,
   |                    ^^^^^^^^^^ move occurs because `self.title` has type `String`, which does not implement the `Copy` trait

๋งŒ์•ฝ Stringํƒ€์ž…์— Copy ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ตฌํ˜„๋˜์–ด์žˆ๋‹ค๋ฉด ์ž๋™์œผ๋กœ copy ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ž๋™์œผ๋กœ ๊ฐ์ฒด ๋ณต์‚ฌ๋ฅผ ํ•ด์ฃผ๊ฒŒ๋˜์ง€๋งŒ, String ํƒ€์ž…์€ Copy ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€์•Š์•˜์œผ๋ฏ€๋กœ ์œ„์™€๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  published๋Š” u32ํƒ€์ž…์˜ ๋ณ€์ˆ˜์ด๋ฏ€๋กœ clone์ด ํ•„์š”์—†์ด ๊ฐ’์ด ๋ณต์‚ฌ๋ฉ๋‹ˆ๋‹ค.

์ด์ „ ์˜ˆ์ œ์—์„œ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ ํ›„ ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ดค์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ Clone๋„ ํŠธ๋ ˆ์ดํŠธ๋‹ˆ๊นŒ ๋น„์Šทํ•˜๊ฒŒ Clone์„ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋“ค์„ ์ธ์ž๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ์š”? ์˜ˆ์ œ์—์„œ ์ฃผ์„์œผ๋กœ๋œ print_info ํ•จ์ˆ˜๋ฅผ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์–ด์„œ ๋‹ค์‹œ ๋นŒ๋“œํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

...
fn print_info(item: &dyn Clone) {
    println!("item implements Clone trait");
}
...
error[E0038]: the trait `Clone` cannot be made into an object
  --> src/main.rs:50:22
   |
50 | fn print_info(item: &dyn Clone) {
   |                      ^^^^^^^^^ `Clone` cannot be made into an object
   |
   = note: the trait cannot be made into an object because it requires `Self: Sized`
   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>

์ปดํŒŒ์ผ๋Ÿฌ ๋ฉ”์„ธ์ง€๊ฐ€ ์•ฝ๊ฐ„ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์ง€๋งŒ ์ด๋ ‡๊ฒŒ ์ƒ๊ฐํ•ด๋ณด๋ฉด ํžŒํŠธ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋กœ ์ „๋‹ฌํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์›๋ž˜์˜ ํƒ€์ž…์ด ๋ญ”์ง€๋ฅผ ์ˆจ๊ธฐ๊ณ  ์—ฌ๋Ÿฌ ํƒ€์ž…์ด ๊ณตํ†ต์œผ๋กœ ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ตฌํ˜„ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ clone ๋ฉ”์†Œ๋“œ์ฒ˜๋Ÿผ Self๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด, ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด์˜ ์›๋ž˜ ํƒ€์ž…์ด ๋ญ”์ง€ ์•Œ์•„์•ผ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ clone ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š” Clone ํŠธ๋ ˆ์ดํŠธ๋Š” ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—๋Ÿฌ ๋ฉ”์„ธ์ง€์—์„œ ์•Œ๋ ค์ฃผ๋Š” Object safety(https://doc.rust-lang.org/reference/items/traits.html#object-safety) ๋ผ๋Š” ๊ทœ์น™๋“ค์ด ์žˆ๋Š”๋ฐ ํŠธ๋ ˆ์ดํŠธ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์“ธ ์ˆ˜ ์žˆ๋Š” ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ฐ€์ ธ์•ผํ•˜๋Š” ๊ทœ์น™๋“ค์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— Sized ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค๊ณ  ์จ์žˆ๋Š”๋ฐ Clone ํŠธ๋ ˆ์ดํŠธ๋Š” ์ƒ์œ„ ํŠธ๋ ˆ์ดํŠธ๋กœ Sized ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์— CloneํŠธ๋ ˆ์ดํŠธ์˜ ์ •์˜๋ฅผ ๋ณด๋ฉด Clone:Sized๋ผ๊ณ  ์จ์žˆ๋Š”๋ฐ Sized ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์ƒ์œ„ ํŠธ๋ ˆ์ดํŠธ๋กœ ๊ฐ€์ง„๋‹ค๋Š” ํ‘œ์‹œ์ž…๋‹ˆ๋‹ค. Sized ํŠธ๋ ˆ์ดํŠธ๋Š” ๋ฐ”๋กœ ํŠธ๋ ˆ์ดํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ํƒ€์ž…๋“ค์ด ์ปดํŒŒ์ผ ์‹œ์ ์— ์–ด๋А ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค๋Š” ํ‘œ์‹œ์ž…๋‹ˆ๋‹ค ์ปดํŒŒ์ผ ํƒ€์ž„์— Self ํƒ€์ž…์˜ ํฌ๊ธฐ๋ฅผ ์•Œ์•„์•ผ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ์—์„œ ์•ˆ์ •์„ฑ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์ด์™€๊ฐ™์ด ์–ด๋–ค ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ ์žํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ, ์†์„ฑ๋งŒ ๋ถ€์—ฌํ•˜๊ณ ์žํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋Ÿฐ ํŠธ๋ ˆ์ดํŠธ๋“ค์„ Marker trait๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ SizedํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์ •์˜๋œ ์œ„์น˜๊ฐ€ std::marker์ž…๋‹ˆ๋‹ค.

๋Ÿฌ์ŠคํŠธ๋Š” ์ด์™€๊ฐ™์ด ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด์„œ ๋ณต์žกํ•ด๋ณด์ด๋Š” ๊ทœ์น™๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณผํ•˜๋‹ค์‹ถ์„ ๋•Œ๋„ ์žˆ์ง€๋งŒ, ์ด๋Ÿฐ ๊ทœ์น™๋“ค์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ƒ๊ฐํ•˜๋ฉด์„œ ๊ฐœ๋ฐœํ•ด์•ผํ•˜๋Š” ์–ธ์–ด๋“ค์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๋Š”๊ฒŒ ์ดํ† ๋ก ์‰ฝ์ง€์•Š์€ ์ผ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด๋ณด์ด๊ณ  ์˜๋ฏธ๋ฅผ ์•Œ ์ˆ˜ ์—†๋Š” ๊ทœ์น™๋“ค์ด์ง€๋งŒ, ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ •์„ฑ์„ ์—ผ๋‘ํ•ด๋‘๊ณ  ์—ฐ์Šต์„ ํ•ด๋‚˜๊ฐ„๋‹ค๋ฉด ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์ž‘๋‹จ๊ณ„์—์„œ๋Š” ๋ชจ๋“  ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๋‹ค ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ๋งŒ ๊ธฐ์–ตํ•ด๋‘๊ณ  ์ ์ฐจ ์ต์ˆ™ํ•ด์ง€๋ฉด์„œ ๋” ์ดํ•ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Sized๋‚˜ Copy ํŠธ๋ ˆ์ดํŠธ ๋“ฑ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ• ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ์™ธ ๋‹ค์–‘ํ•œ ๋งˆ์ปค ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์žˆ์ง€๋งŒ, ์ด ์ฑ…์˜ ์ˆ˜์ค€์„ ๋„˜์–ด์„œ๊ธฐ๋•Œ๋ฌธ์— ์ž์„ธํžˆ ์„ค๋ช…ํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ๊ธธ๊ฒŒ Clone ํŠธ๋ ˆ์ดํŠธ์˜ ๊ตฌํ˜„์„ ์„ค๋ช…ํ–ˆ์ง€๋งŒ, ์‚ฌ์‹ค์€ ์ด๋ ‡๊ฒŒ ์ง์ ‘ ๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. derive[Clone]์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ์ž๋™์œผ๋กœ CloneํŠธ๋ ˆ์ดํŠธ์˜ ๊ตฌํ˜„์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

#[derive(Debug, Clone)]
struct Book {
    title: String,
    author: String,
    published: u32,
}
...

๋””ํดํŠธ ๊ฐ’์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” Default

Default ํŠธ๋ ˆ์ดํŠธ๋Š” ๊ตฌ์กฐ์ฒด์˜ ๊ฐ ํ•„๋“œ๋ฅผ ๋””ํดํŠธ๊ฐ’์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” Default ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€์•Š๊ณ  derive(Default) ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์„œ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

// src/trait_default/main.rs
#[derive(Debug, Clone, Default)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

fn main() {
    let book = Book::default();
    let book_clone = book.clone();
    println!("{:?}", book_clone);
}
gkim@gkim-laptop:~/study/my-rust-book$ cargo run --bin trait_default
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s
     Running `target/debug/trait_default`
Book { title: "", author: "", published: 0 }

DefaultํŠธ๋ ˆ์ดํŠธ๋Š” default๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. default ๋ฉ”์†Œ๋“œ๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์ •์  ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ โ€œํƒ€์ž…์ด๋ฆ„::default()โ€ ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„ํ˜น ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฐ’๋“ค์ด ๊ฐœ๋ฐœ์ž์˜ ์˜๋„์™€ ๋‹ค๋ฅผ ๋•Œ๋งŒ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ฐ’์ด ๊ฐ™์€์ง€ ๋น„๊ตํ•˜๋Š” PartialEq

PartialEq๋Š” ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ์ž…๋‹ˆ๋‹ค.

// src/trait_partialeq_first/main.rs
#[derive(Debug, Clone, Default)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

impl PartialEq for Book {
    fn eq(&self, other: &Self) -> bool {
        self.title == other.title && self.author == other.author
    }
}

fn main() {
    let second = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
    };

    let first = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20190812,
    };

    if second == first {
        println!(
            "Yes, they are same book but different release {} != {}.",
            first.published, second.published
        );
    }
}
$ cargo run --bin trait_partialeq_first
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/trait_partialeq_first`
Yes, this book is writtend by Person { name: "Steve Klabnik", age: 30 }

์œ„์™€ ๊ฐ™์ด ๋‘ ์ฑ…์ด ๊ฐ™์€ ์ฑ…์ธ์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ์ฑ… ์ œ๋ชฉ๊ณผ ์ €์ž ์ด๋ฆ„์„ ํ™•์ธํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋ ˆ์ดํŠธ ์ด๋ฆ„์ด PartialEq๋ผ๊ณ ํ•ด์„œ ์™œ Partial์ด๋ผ๋Š” ์ด๋ฆ„์ด ๋“ค์–ด๊ฐ”๋Š”์ง€ ์˜์•„ํ•˜๊ฒŒ ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์™„์ „ํ•˜๊ฒŒ ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์œ„์™€๊ฐ™์ด ์ข€๋” ๋„“์€ ์˜๋ฏธ์—์„œ ์ผ๋ถ€ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง„ ๊ฐ์ฒด๋„ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์œ ์—ฐ์„ฑ์„ ๊ฐ–๋Š”๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ์‰ฌ์šธ๋“ฏํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋กœ ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

// src/trait_partialeq_second/main.rs
#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}

#[derive(Debug, Clone, Default)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

impl PartialEq for Book {
    fn eq(&self, other: &Self) -> bool {
        self.title == other.title && self.author == other.author
    }
}

impl PartialEq<Person> for Book {
    fn eq(&self, other: &Person) -> bool {
        self.author.contains(&other.name)
    }
}

impl PartialEq<Book> for Person {
    fn eq(&self, other: &Book) -> bool {
        other.author.contains(&self.name)
    }
}

fn main() {
    let second = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
    };
    let steve = Person {
        name: "Steve Klabnik".to_string(),
        age: 30,
    };
    if second == steve {
        println!("Yes, this book is writtend by {:?}", steve);
    }
}
$ cargo run --bin trait_partialeq_second
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/trait_partialeq_second`
Yes, this book is writtend by Person { name: "Steve Klabnik", age: 30 }

Book ํƒ€์ž…๊ณผ Person ํƒ€์ž…์€ ๋™์ผํ•œ ๊ฐ์ฒด๊ฐ€ ๋  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ผ๋ถ€ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ–๋Š”์ง€๋ฅผ ๋น„๊ตํ•  ์ˆ˜๋Š” ์žˆ๊ฒ ์ง€์š”. ์•„์ง ์ œ๋„ˆ๋ฆญ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ, PartialEq์— ์–ด๋–ค ํƒ€์ž… ๋ฐ”์ธ๋”ฉ์„ ์“ฐ๋Š”์ง€์— ๋”ฐ๋ผ์„œ ๋น„๊ตํ•  ๋Œ€์ƒ์˜ ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ๋งŒ ์ƒ๊ฐํ•ด๋ณด์‹œ๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

PartialEq ์™ธ์—๋„ Eq ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณดํ†ต ์šฐ๋ฆฌ๊ฐ€ == ์—ฐ์‚ฐ์ž๋กœ ๋น„๊ตํ•  ๋•Œ๋Š” PartialEq๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

PartialEq์™€ Eq ํŠธ๋ ˆ์ดํŠธ์˜ ์ฐจ์ด

๋Ÿฌ์ŠคํŠธ์—์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ตํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ๊ฐ€ PartialEq๋ผ๋Š” ๊ฒƒ์ด ์ด์ƒํ•˜๊ฒŒ ๋А๊ปด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ ์ด๋ฆ„์— ์ผ๋ถ€๋ถ„(Partial)์ด๋ผ๋Š” ์˜๋ฏธ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”์ง€, ์™œ Eq๊ฐ€ ๊ธฐ๋ณธ์ด ์•„๋‹Œ์ง€ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ •์˜๋งŒ ๋†“๊ณ  ๋ณธ๋‹ค๋ฉด PartialEq๋Š” Partial-equivalence ๊ด€๊ณ„(https://en.wikipedia.org/wiki/Partial_equivalence_relation)๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ˆ˜ํ•™์ ์ธ ํ‘œํ˜„๋“ค์„ ๋‹จ์ˆœํ™”์‹œ์ผœ์„œ ์ƒ๊ฐํ•ด๋ณด๋ฉด

  1. a=b์ผ๋•Œ b=a๋ฅผ ๋งŒ์กฑํ•˜๊ณ 
  2. a=b์ด๊ณ  b=c์ผ๋•Œ a=c๋ฅผ ๋งŒ์กฑํ•˜๋Š”์ง€๋ฅผ

์ด๋ ‡๊ฒŒ 2๊ฐ€์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Eq ํŠธ๋ ˆ์ดํŠธ๋Š” equivalence ๊ด€๊ณ„(https://en.wikipedia.org/wiki/Equivalence_relation)๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ธ๋ฐ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ˆ˜ํ•™์ ์ธ ํ‘œํ˜„๋“ค์„ ๋‹จ์ˆœํ™”์‹œ์ผœ๋ณด๋ฉด

  1. a==a๋ฅผ ๋งŒ์กฑํ•˜๋Š”์ง€

ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๋‘˜๋‹ค ์ˆ˜ํ•™์ ์ธ ๋‚ด์šฉ๋“ค์ด๋ผ ์‚ฌ์‹ค ์˜๋ฏธ๋ฅผ ์•Œ๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ’์„ ๋น„๊ตํ•  ๋•Œ๋Š” PartialEq๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๋‹ค. ๊ฐ’์„ ๋น„๊ตํ•  ์ˆ˜ ์—†๋Š” ์˜ˆ์™ธ์ ์ธ ์ผ€์ด์Šค๋“ค์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— PartialEq๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์˜ˆ์™ธ์ ์ธ ์ผ€์ด์Šค๋“ค ์ค‘์— ๋Œ€ํ‘œ์ ์œผ๋กœ ์†Œ๊ฐœํ•˜๋Š” ๊ฒƒ์ด ๋ถ€๋™์†Œ์ˆ˜์  ์—ฐ์‚ฐ์—์„œ ๋ญ”๊ฐ€ ์—ฐ์‚ฐ์ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” std::f32::NAN์ด๋ผ๋Š” ๊ฐ’์„ ๋น„๊ตํ• ๋•Œ PartialEq๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

assert_eq๋งคํฌ๋กœ๋ฅผ ์ด์šฉํ•ด์„œ std::f32::NAN์„ ๋น„๊ตํ•ด๋ณด๋ฉด ๋ณด๊ธฐ์—๋Š” ์„œ๋กœ ๊ฐ™์œผ๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ์—†์„๊ฒƒ ๊ฐ™์ง€๋งŒ, ์„œ๋กœ ๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ๊ฒฐ๊ตญ ๊ฐ™์ง€ ์•Š๋‹ค๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋˜๊ณ , ํŒจ๋‹‰์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

fn main() {
    assert_eq!(std::f32::NAN, std::f32::NAN);
}

์ˆ˜ํ•™์ ์œผ๋กœ ์ˆซ์ž ์•„๋‹˜๊ณผ ์ˆซ์ž ์•„๋‹˜์„ ๋น„๊ตํ•œ๋‹ค๋Š” ๊ฒƒ์ด ์ •์˜๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๊ฐ’์ด ๊ฐ™์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•˜๋„๋ก ๋งŒ๋“  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ๋“ฑ ๋Œ€๋ถ€๋ถ„์˜ ์–ธ์–ด๋“ค๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์‹ค ์ด๊ฒŒ ๋ฌด์Šจ ์˜๋ฏธ์ธ์ง€ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์œ„์— ์ฑ…๊ณผ ์ €์ž๋ฅผ ๋น„๊ตํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ์กฐ๊ธˆ ๋” ํ™•์žฅํ•ด๋ณด๋ฉด์„œ ์ƒ๊ฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

//src/trait_partialeq_eq/main.rs
#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}

#[derive(Debug, Clone, Default)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

impl PartialEq for Book {
    fn eq(&self, other: &Self) -> bool {
        self.title == other.title && self.author == other.author
    }
}

impl PartialEq<Person> for Book {
    fn eq(&self, other: &Person) -> bool {
        if self.author.contains("Unknown") {
            return false;
        }
        self.author.contains(&other.name)
    }
}

impl PartialEq<Book> for Person {
    fn eq(&self, other: &Book) -> bool {
        if self.name.contains("Unknown") {
            return false;
        }
        other.author.contains(&self.name)
    }
}

fn main() {
    let second = Book {
        title: String::from("Necronomicon"),
        author: String::from("Unknown"),
        published: 20230228,
    };
    let unknown = Person {
        name: "Unknown".to_string(),
        age: 30,
    };
    if second == unknown {
        println!("Yes, this book is writtend by {:?}.", unknown);
    } else {
        println!("No, we don't know who wrote it.")
    }
}
$ cargo run --bin trait_partialeq_eq
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `/home/gkim/study/my-rust-book/target/debug/trait_partialeq_eq`
No, we don't know who wrote it.

์ฑ…์˜ ์ €์ž๋„ Unknown์ด๊ณ , ์‚ฌ๋žŒ์˜ ์ด๋ฆ„๋„ Unknown์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ด ์ฑ… ์ €์ž์™€ ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์ด ๊ฐ™์€ ๊ฒƒ์ผ๊นŒ์š”? ์ด ์ฑ…์„ ์ด ์‚ฌ๋žŒ์ด ์ผ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ‘œ๊ธฐ๋Š” ๊ฐ™์ง€๋งŒ ๋น„๊ตํ•  ์ˆ˜ ์—†๋Š” ๊ฐ’๋“ค์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ, ์ด๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— PartialEq์ด๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ Eq๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋Š” ์–ธ์ œ์ผ๊นŒ์š”? Eq๋Š” ํ•ญ์ƒ ์ •ํ™•ํ•˜๊ฒŒ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. "Unknown"๊ฐ™์ด ๊ฐ™๋‹ค๊ณ  ๋น„๊ตํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•˜์ง€์•Š๊ณ  ํ•ญ์ƒ ์–ด๋–ค ๊ฐ’์ด๋“  ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…๋งŒ Eq๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์œผ๋กœ ํ‚ค์™€ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” HashMap๊ฐ™์€ ์ž๋ฃŒ๊ตฌ์กฐ์—์„œ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ Eq ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ตฌํ˜„๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

PartialEq์˜ ์‚ฌ์šฉ ์˜ˆ์ œ

์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•œ ๋ฌธ์ž๋กœ๋œ ๋ช…๋ น์„ ์ž…๋ ฅ๋ฐ›๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// src/trait_partialeq_assert.main.rs
use std::io;

#[derive(Debug, PartialEq)]
pub enum Command {
    Help,
    Quit,
    Execute(String),
    Run,
}

fn user_input() -> Result<Command, String> {
    println!("input h/q/r/e: ");
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => match input.as_str().strip_suffix("\n") {
            Some("h") => return Ok(Command::Help),
            Some("q") => return Ok(Command::Quit),
            Some("r") => return Ok(Command::Run),
            Some("e") => return Ok(Command::Execute(format!("NOT IMPLEMENTED YET!"))),
            _ => return Err(format!("Wrong input: {input}")),
        },
        Err(error) => return Err(format!("Wrong input: {error}")),
    }
}

fn main() {
    let com: Command = user_input().expect("Wrong input");
    let p = String::new();

    assert_ne!(com, Command::Execute(p));
    match com {
        Command::Help => println!("show help message"),
        Command::Quit => return,
        Command::Run => println!("do something"),
        Command::Execute(path) => println!("execute {path}"),
    }
}
$ cargo run --bin trait_partialeq_assert
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/trait_partialeq_assert`
input h/q/r/e: 
r
do something

ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๋ฉด h/q/r ์ค‘์— ํ•˜๋‚˜๋ฅผ ์ž…๋ ฅํ•˜๋ผ๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ r์„ ์ž…๋ ฅํ•˜๊ณ  ์—”ํ„ฐ๋ฅผ ์น˜๋ฉด โ€œdo somethingโ€์ด๋ผ๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด โ€œdo somethingโ€์„ ์ถœ๋ ฅํ•˜๊ฒŒ ์•„๋‹ˆ๋ผ ์‹ค์ œ๋กœ ๋ญ”๊ฐ€๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.user_inputํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ e๋ผ๋Š” ๋ช…๋ น์„ ์ž…๋ ฅ๋ฐ›์œผ๋ฉด Command::Execute(์ถ”๊ฐ€ ๋ฉ”์„ธ์ง€)๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  mainํ•จ์ˆ˜๋Š” ๊ฑฐ๊ธฐ์— ๋งž๋Š” ์ฒ˜๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์•„์ง ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์™„๋ฃŒ๋œ๊ฒŒ ์•„๋‹ˆ๋ผ์„œ mainํ•จ์ˆ˜์—์„œ assert_ne! ๋งคํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•ด์„œ Command::Execute ์ž…๋ ฅ์„ ๋ฐ›์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ค‘๋‹จ๋˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ถ”ํ›„์— Command::Execute๋ช…๋ น์— ๋”ฐ๋ผ ์‹คํ–‰๋  ์ฝ”๋“œ๋ฅผ ๋จผ์ € ๊ตฌํ˜„ํ•œ ํ›„์— mainํ•จ์ˆ˜์—์„œ ์‹คํ–‰๋˜๋„๋ก ๋งŒ๋“ค ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต ์ž‘์—…์ค‘์ธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ• ๋•Œ assert๋‚˜ assert_eq, assert_ne๋“ฑ์˜ ๋งคํฌ๋กœ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ๋„ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฐ assert๊ด€๋ จ ๋งคํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ PartialEq์˜ ๊ตฌํ˜„์ด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์™œ ํ•„์š”ํ•œ์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋‹จ Command ํƒ€์ž…์— ์žˆ๋Š” derive๋ฅผ ๋นผ๊ณ  ๋นŒ๋“œํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€๊ฐ™์ด ์ด์ƒํ•œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

...
//#[derive(Debug, PartialEq)]
pub enum Command {
    Help,
    Quit,
    Execute(String),
    Run,
}
...
$ cargo run --bin trait_partialeq_assert
   Compiling ex v0.1.0 (/Users/user/ex)
error[E0369]: binary operation `==` cannot be applied to type `Command`
  --> src/main.rs:29:5
   |
29 |     assert_ne!(com, Command::Execute(p));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |     |
   |     Command
   |     Command
   |
note: an implementation of `PartialEq` might be missing for `Command`
  --> src/main.rs:3:1
   |
3  | pub enum Command {
   | ^^^^^^^^^^^^^^^^ must implement `PartialEq`
   = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Command` with `#[derive(PartialEq)]`
   |
3  + #[derive(PartialEq)]
4  | pub enum Command {
   |

error[E0277]: `Command` doesn't implement `Debug`
  --> src/main.rs:29:5
   |
29 |     assert_ne!(com, Command::Execute(p));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Command` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `Command`
   = note: add `#[derive(Debug)]` to `Command` or manually `impl Debug for Command`
   = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Command` with `#[derive(Debug)]`
   |
3  + #[derive(Debug)]
4  | pub enum Command {
   |

Some errors have detailed explanations: E0277, E0369.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `ex` (bin "ex") due to 3 previous errors

๊ฐ€์žฅ ๋จผ์ € ๋ฐœ์ƒํ•œ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋ฉด assert_ne! ๋งคํฌ๋กœ๊ฐ€ ์‹คํ–‰๋  ๋•Œ โ€˜==โ€™ ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด์„œ ๋‘๊ฐœ์˜ ๊ฐ’์ด ๊ฐ™์€์ง€๋ฅผ ํ™•์ธํ•˜๋Š”๋ฐ, Command ํƒ€์ž…์€ โ€˜==โ€™ ์—ฐ์‚ฐ์ž๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋ง์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์นœ์ ˆํ•˜๊ฒŒ๋„ Commandํƒ€์ž…์— PartialEq ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๊ฒŒ ํ•„์š”ํ•˜๋‹ค๋Š” ์„ค๋ช…์„ ํ•ด์ฃผ๋ฉด์„œ #[derive(PartialEq)]๋ฅผ ํƒ€์ž…์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ์—๋Š” ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ assert_ne! ๋งคํฌ๋กœ๊ฐ€ Debug ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋‹ˆ PartialEq์™€ ๊ฐ™์ด #[derive(Debug)]๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ผ๋Š” ์•ˆ๋‚ด ๋ฉ”์„ธ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ผ๋‹จ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์•Œ๋ ค์ฃผ๋Š”๋Œ€๋กœ Debug์™€ PartialEq์˜ ๊ตฌํ˜„์„ ๋‹ค์‹œ ์ถ”๊ฐ€ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

...
#[derive(Debug, PartialEq)]
pub enum Command {
    Help,
    Quit,
    Execute(String),
    Run,
}
...

Debug์™€ PartialEq ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋”๋‹ˆ ๋ฌธ์ œ์—†์ด ๋นŒ๋“œ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™€ ๊ฐ™์ด ์ผ๋ฐ˜์ ์œผ๋กœ ๋‘๊ฐœ์˜ ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” ๊ฒฝ์šฐ์— PartialEq ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

PartialEq์™€ Eq์˜ ์‚ฌ์šฉ ์˜ˆ์ œ

๊ทธ๋Ÿผ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ’์„ ๋น„๊ตํ•  ๋•Œ PartialEq๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•œ๋‹ค๋ฉด ๊ตณ์ด Eq ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋ฌด์—‡์„๊นŒ์š”? ๋ฐ”๋กœ ๊ตฌ์กฐ์ฒด๋ฅผ HashMap์˜ ํ‚ค ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์ž…๋‹ˆ๋‹ค.

// src/trait_partialeq_eq_hashmap/main.rs
#[derive(PartialEq, Eq, Hash)]
struct MyKey {
    x: i32,
    y: i32,
}

struct MyVal {
    distance_from_co_origin: f32,
}

fn main() {
    let mut map = HashMap::new();
    map.insert(
        MyKey { x: 3, y: 4 },
        MyVal {
            distance_from_co_origin: 5.0,
        },
    );
}

MyKey๋Š” ์ ์˜ ์ขŒํ‘œ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. MyVal์€ ์›์ ์œผ๋กœ๋ถ€ํ„ฐ ์ ์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ์ ๋“ค์˜ ์›์ ์œผ๋กœ๋ถ€ํ„ฐ ๊ฑฐ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ•ด์‹œ๋งต์„ ๋งŒ๋“ค์–ด๋ดค์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ MyKey ๊ตฌ์กฐ์ฒด์— PartialEq์™€ Eq ํŠธ๋ ˆ์ดํŠธ์˜ ๊ตฌํ˜„์ด ์—†๋‹ค๋ฉด ๋นŒ๋“œ๊ฐ€ ์•ˆ๋ฉ๋‹ˆ๋‹ค. PartialEq๋Š” Eq์˜ ์†Œ์ง‘ํ•ฉ์ด๋ฏ€๋กœ Eq๊ตฌํ˜„์„ ์œ„ํ•ด์„œ๋Š” PartialEq๊ฐ€ ํ•ญ์ƒ ๊ฐ™์ด ๊ตฌํ˜„๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  HashMap์—์„œ ํ‚ค ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ํ‘œ์‹œ๋ฅผ ํ•˜๊ธฐ์œ„ํ•ด Hash ํŠธ๋ ˆ์ดํŠธ๋„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

HashMap์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ์— ๋‹ค์‹œ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” Eq๋งŒ ๋ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

ํฌ๊ธฐ๋ฅผ ๋น„๊ตํ•˜๋Š” std::cmp::Orderingํƒ€์ž…๊ณผ std::cmp::OrdํŠธ๋ ˆ์ดํŠธ

๋‘ ๊ฐ์ฒด๊ฐ€ ๋™์ผํ•œ์ง€๋ฅผ ํŒ๋‹จํ•˜๋Š” std::cmp::PartialEq ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์•Œ์•„๋ดค์œผ๋‹ˆ ์ด๋ฒˆ์—๋Š” ํฌ๊ธฐ๋ฅผ ๋น„๊ตํ•˜๋Š” std::cmp::PartialOrd ํŠธ๋ ˆ์ดํŠธ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‘ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// src/trait_partialord/main.rs
use std::cmp::Ordering;

#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: i32,
    height: i32,
}

impl PartialOrd for Person {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.height <= 0 || other.height <= 0 {
            return None;
        }

        if self.height > other.height {
            Some(Ordering::Greater)
        } else if self.height < other.height {
            Some(Ordering::Less)
        } else {
            Some(Ordering::Equal)
        }
    }
}

fn main() {
    let alpha = Person {
        name: "alpha".to_owned(),
        age: 10,
        height: 110,
    };
    let beta = Person {
        name: "beta".to_owned(),
        age: 10,
        height: 100,
    };

    if alpha > beta {
        println!("{} is taller.", alpha.name);
    }
    if alpha.partial_cmp(&beta).unwrap() == Ordering::Greater {
        println!("{} is taller.", alpha.name);
    }
}

์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผํ•  ๊ฒƒ์€ PartialOrd ํŠธ๋ ˆ์ดํŠธ์˜ partial_cmp ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” Option<Ordering>์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์™œ Option์„ ์‚ฌ์šฉํ•˜๋Š”์ง€๋Š” ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. height ๊ฐ’์ด 0์ด๊ฑฐ๋‚˜ ์Œ์ˆ˜์ธ ๊ฒฝ์šฐ, ์•„์ง ๊ฐ์ฒด๊ฐ€ ์ œ๋Œ€๋กœ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๋กœ ์ธํ•ด ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊นจ์กŒ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋‹จ์ˆœํžˆ ๋น„๊ต๋งŒ ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋น„๊ตํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋Ÿฐ ์—๋Ÿฌ ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ์œ„ํ•ด Option์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. Rust์–ธ์–ด๊ฐ€ ์–ผ๋งˆ๋‚˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ์— ์ฒ ์ €ํ•œ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  PartialOrd ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•œ๊ฐ€์ง€ ๋” ์ƒˆ๋กญ๊ฒŒ ์•Œ์•„์•ผํ•  ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

partial_cmp๋ฉ”์†Œ๋“œ์—์„œ ๊ฐ€์žฅ ๋จผ์ € ์—๋Ÿฌ ์ƒํ™ฉ์„ ํ™•์ธํ•œ ์ดํ›„์—๋Š” ์‹ค์ œ๋กœ ๋น„๊ตํ•ด์•ผํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. std::cmp::PartialOrd๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ์˜ partial_cmp ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’์ด std::cmp::Ordering์ด๋ผ๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค. Ordering์€ enum ํƒ€์ž…์œผ๋กœ Greater, Less, Equal์ด๋ผ๋Š” 3๊ฐ€์ง€ ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋” ํฌ๋‹ค๋ฉด Ordering::Greater๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ž‘์œผ๋ฉด Ordering::Less, ๊ฐ™์œผ๋ฉด Ordering::Equal์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

mainํ•จ์ˆ˜์—์„œ๋Š” ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋Š” 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ๋ฒˆ์งธ๋Š” ์ง๊ด€์ ์œผ๋กœ โ€˜>โ€™ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. PartialOrd ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ตฌํ˜„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด๊ฐ„์— โ€˜>โ€™์™€ โ€˜<โ€™ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  โ€˜==โ€™ ์—ฐ์‚ฐ์ž๋Š” PartialEq ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ตฌํ˜„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ(derive(PartialEq)๋กœ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค)์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ ๋งˆ์ง€๋ง‰์—๋Š” partial_cmp ๋ฉ”์†Œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. '<', '>', '==' ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•ด์•ผํ•  ๋•Œ โ€˜<โ€™๊ฐ™์€ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ์ด๋ ‡๊ฒŒ partial_cmp ๋ฉ”์†Œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด์„œ ๊ฒฐ๊ณผ๊ฐ’์„ ์ €์žฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ๋‘ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋น„๊ตํ•˜๋ฉด ์ƒ๊ฐ๋‚˜๋Š”๊ฒŒ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด์ง€์š”. ํ•œ๋ฐ˜์— ์žˆ๋Š” ํ•™์ƒ๋“ค์„ ํ‚ค์— ๋”ฐ๋ผ ์ •๋ ฌํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

// src/trait_partialord_sort_first/main.rs
use std::cmp::Ordering;

#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: i32,
    height: i32,
}

impl PartialOrd for Person {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.height <= 0 || other.height <= 0 {
            return None;
        }

        if self.height > other.height {
            Some(Ordering::Greater)
        } else if self.height < other.height {
            Some(Ordering::Less)
        } else {
            Some(Ordering::Equal)
        }
    }
}

fn class_sorting(people: &mut Vec<Person>) {
    let len = people.len();

    for i in 0..(len - 1) {
        for j in (i + 1)..len {
            if people[i] > people[j] {
                people.swap(i, j);
            }
        }
    }
}

fn main() {
    let mut class: Vec<Person> = vec![
        Person {
            name: "aaa".to_owned(),
            age: 10,
            height: 110,
        },
        Person {
            name: "bbb".to_owned(),
            age: 10,
            height: 100,
        },
        Person {
            name: "ccc".to_owned(),
            age: 10,
            height: 120,
        },
        Person {
            name: "ddd".to_owned(),
            age: 10,
            height: 90,
        },
    ];

    class_sorting(&mut class);

    for p in class.iter() {
        println!("{} is {}", p.name, p.height);
    }
}
$ cargo run --bin trait_partialord_sort_first
   Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.45s
     Running `target/debug/trait_partialord_sort_first`
ddd is 90
bbb is 100
aaa is 110
ccc is 120

๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ทธ๋ ‡๋“ฏ์ด Rust์˜ ๋ฒกํ„ฐ ํƒ€์ž…์—๋„ ์ •๋ ฌ์„ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ ๋ฒกํ„ฐ์˜ ๊ฐ ๋ฐ์ดํ„ฐ๋“ค์„ ๋น„๊ตํ•˜๋Š” ํด๋กœ์ €๋ฅผ ์ „๋‹ฌํ•ด์•ผํ•˜๋ฏ€๋กœ ์ด๋•Œ๋Š” โ€˜>โ€™๊ฐ™์€ ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ž๊ฐ€ ์•„๋‹ˆ๋ผ partial_cmp ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜ ์—์ œ๋Š” ๋ฐฑํ„ฐ์˜ sort_by ๋ฉ”์†Œ๋“œ์™€ PartialOrd ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

// src/trait_partialord_sort_second/main.rs
use std::cmp::Ordering;

#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: i32,
    height: i32,
}

impl PartialOrd for Person {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.height <= 0 || other.height <= 0 {
            return None;
        }

        if self.height > other.height {
            Some(Ordering::Greater)
        } else if self.height < other.height {
            Some(Ordering::Less)
        } else {
            Some(Ordering::Equal)
        }
    }
}

fn main() {
    let mut class: Vec<Person> = vec![
        Person {
            name: "aaa".to_owned(),
            age: 10,
            height: 110,
        },
        Person {
            name: "bbb".to_owned(),
            age: 10,
            height: 100,
        },
        Person {
            name: "ccc".to_owned(),
            age: 10,
            height: 120,
        },
        Person {
            name: "ddd".to_owned(),
            age: 10,
            height: 90,
        },
    ];

    class.sort_by(|a, b| a.partial_cmp(b).unwrap());

    for p in class.iter() {
        println!("{} is {}", p.name, p.height);
    }
}
$ cargo run --bin trait_partialord_sort_second
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.35s
     Running `target/debug/trait_partialord_sort_second`
ddd is 90
bbb is 100
aaa is 110
ccc is 120

๋ฒกํ„ฐ(Vector)๋Š” ๋‹ค์Œ์— ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” partial_cmp ๋ฉ”์†Œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด์„œ๋งŒ ๋ด์ฃผ์„ธ์š”.

ํƒ€์ž…์„ ๋ฐ”๊ฟ”์ฃผ๋Š” From/Into ํŠธ๋ ˆ์ดํŠธ์™€ TryFrom/TryInto ํŠธ๋ ˆ์ดํŠธ

From๊ณผ Into

ํŠน์ • ํƒ€์ž…์„ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ฐ”๊ฟ€๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ์ž…๋‹ˆ๋‹ค.

์ด ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์ €์ฒ˜๋Ÿผ C/C++๋งŒ ์‚ฌ์šฉํ•˜์‹œ๋˜ ๋ถ„๋“ค๊ป˜๋Š” ํ•„์š”์„ฑ์ด ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋„ ์ฒ˜์Œ์—๋Š” ์ด๊ฒŒ ๊ตณ์ด ์™œ ํ•„์š”ํ•œ๊ฐ€ ์ƒ๊ฐํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ•œ๋ฒˆ ์‚ฌ์šฉํ•ด๋ณด๋‹ˆ ์™œ ํ•„์š”ํ•œ์ง€ ์ดํ•ด๊ฐ€๋˜์„œ ์ ์  ๋” ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ฒŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ C/C++๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜๋Š” ๊ฒฝ์šฐ, ํ•œ ๋ชจ๋“ˆ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ• ๋•Œ ๊ตฌ์กฐ์ฒด์˜ ๊ฐ ํ•„๋“œ๋ฅผ ์ชผ๊ฐœ์„œ ์ „๋‹ฌํ•˜๋Š”๊ฒŒ ๋ณดํ†ต์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ๋ชจ๋“ˆ์€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋ฐ์ดํ„ฐ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๊ฑฐ๋‚˜, ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๋“ฑ์˜ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ From/Into๊ฐ™์€ ํƒ€์ž…์„ ๋ณ€ํ™˜ํ•˜๋Š” ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ๋ชจ๋“ˆ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๊ณผ์ •์—์„œ ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ Bookํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ u32ํƒ€์ž…์˜ ISBN ์ˆซ์ž๋กœ ๋ฐ”๊พธ๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

// src/trait_from/main.rs
#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
    isbn: String,
}

impl From<Book> for u32 {
    fn from(book: Book) -> u32 {
        book.isbn.parse().unwrap_or(0)
    }
}

fn main() {
    let the_book = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
        isbn: String::from("718503105"),
    };

    let rust_in_action = Book {
        title: String::from("Rust in Action"),
        author: String::from("Tim McNamara"),
        published: 20210810,
        isbn: String::from("1617294551"),
    };

    let isbn: u32 = the_book.into();
    let isbn2 = u32::from(rust_in_action);
    println!("The book is {isbn} and Rust in Action is {isbn2}");
}
$ cargo run --bin trait_from
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.34s
     Running `target/debug/trait_from`
The book is 718503105 and Rust in Action is 1617294551

Bookํƒ€์ž…์„ u32๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ ์ตœ์ข… ์ƒ์„ฑ๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” u32ํƒ€์ž…์ด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ u32ํƒ€์ž…์„ ์œ„ํ•ด From<Book> ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. from์ด๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒŒ๋˜๋Š”๋ฐ ์ธ์ž๋ฅผ Book ํƒ€์ž…์„ ๋ฐ›๊ณ , ๋ฐ˜ํ™˜๊ฐ’์ด u32๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๋ณดํ†ต From์„ ๋” ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š”๋ฐ, From์„ ๊ตฌํ˜„ํ•˜๋ฉด Into๊ฐ€ ์ž๋™์œผ๋กœ ๊ตฌํ˜„๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ๋ด๋„ into ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ into ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

From<Book>์—์„œ From์€ ํŠธ๋ ˆ์ดํŠธ์˜ ์ด๋ฆ„์ด๊ณ , Book์€ From ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ตฌํ˜„๋  ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ œ๋„ˆ๋ฆญ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ œ๋„ˆ๋ฆญ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๋‹ค์Œ์— ๋‹ค์‹œ ์ด์•ผ๊ธฐํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” From ํŠธ๋ ˆ์ดํŠธ๋ฅผ Book ํƒ€์ž…์„ ์œ„ํ•ด ๊ตฌํ˜„ํ–ˆ๋‹ค๊ณ  ์ดํ•ดํ•ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

TryFrom๊ณผ TryInto

์ข€ ๋” ๊ฐ„๋‹จํ•œ From/Into๋ฅผ ์•Œ์•„๋ดค์œผ๋‹ˆ, ์ด๋ฒˆ์—๋Š” ์กฐ๊ธˆ ๋” ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” TryFrom/TryInto์˜ ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฆ„์— Try๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์„ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, ์‹œ๋„๋ฅผ ํ•ด๋ณด๊ณ  ์•ˆ๋˜๋ฉด ์‹คํŒจ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด From/Into์™€ ์ฐจ์ด์ ์ž…๋‹ˆ๋‹ค. ์ด์ „ ์˜ˆ์ œ์—์„œ From/Into์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋ณด๋ฉด Resultํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ๊ณง๋ฐ”๋กœ u32๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹คํŒจ์— ๋Œ€ํ•œ ๊ณ ๋ ค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ์˜ˆ์ œ์—์„œ๋Š” TryFrom ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , try_from ๋ฉ”์†Œ๋“œ์—์„œ Result๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
    isbn: String,
}

impl TryFrom<Book> for u32 {
    type Error = u32;

    fn try_from(book: Book) -> Result<u32, Self::Error> {
        match book.isbn.parse::<u32>() {
            Ok(n) => Ok(n),
            Err(_) => Err(0),
        }
    }
}

fn main() {
    let the_book = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
        isbn: String::from("718503105"),
    };

    let rust_in_action = Book {
        title: String::from("Rust in Action"),
        author: String::from("Tim McNamara"),
        published: 20210810,
        isbn: String::from("1617294551"),
    };

    let isbn: Result<u32, u32> = the_book.try_into();
    let isbn2 = u32::try_from(rust_in_action);
    println!("The book is {:?} and Rust in Action is {:?}", isbn, isbn2);
}

TryFrom ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ดค์Šต๋‹ˆ๋‹ค. ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์„ ๋ณด๋ฉด ๊ฐ€์žฅ ์ฒ˜์Œ ํ•œ ์ผ์ด Error ํƒ€์ž…์œผ๋กœ ์–ด๋А ํƒ€์ž…์„ ์ง€์ •ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค. ์ฑ…์˜ ISBN์€ 0์ด ๋  ์ˆ˜ ์—†์œผ๋‹ˆ ์—๋Ÿฌ ํƒ€์ž…์„ u32 ํƒ€์ž… ์ •์ˆ˜๋กœ ์ง€์ •ํ•˜๊ณ  ์—๋Ÿฌ์˜ ๊ฒฝ์šฐ Err(0)์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“ค์–ด๋ดค์Šต๋‹ˆ๋‹ค. ๋ณด๋‹ค ์นœ์ ˆํ•˜๊ฒŒ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ์ง€์ •ํ•˜๊ณ  ์‹ถ์œผ๋ฉด Errorํƒ€์ž…์„ &โ€™static str ํƒ€์ž…์ด๋‚˜ String ํƒ€์ž…์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  try_from ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ๋ฐ˜ํ™˜๊ฐ’์ด Result<u32, Self::Error>์ž…๋‹ˆ๋‹ค. from๋ฉ”์†Œ๋“œ์—์„œ u32๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๊ณผ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์†Œ๋“œ์˜ ๊ตฌํ˜„์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์ฑ… ๋ฐ์ดํ„ฐ์— ์žˆ๋Š” isbn๊ฐ’์ด ์ •์ƒ์ ์ธ ๊ฐ’์ด๋ผ๋ฉด Ok(u32)๊ฐ€ ๋ฐ˜ํ™˜๋  ๊ฒƒ์ด๊ณ , ์ •์ƒ์ ์ธ ๊ฐ’์ด ์•„๋‹ˆ๋ผ์„œ ํŒŒ์‹ฑ์ค‘์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด Err(0)์ด ๋ฐ˜ํ™˜๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ƒํ™ฉ์— ๋”ฐ๋ผ From์„ ์“ธ ๊ฒƒ์ธ์ง€, TryFrom์„ ์“ธ ๊ฒƒ์ธ์ง€ ์„ ํƒํ•˜๋ฉด๋˜๊ฒ ์ง€๋งŒ, ๋ณด๋‹ค ์œ ์—ฐํ•œ ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ๋Š” TryFrom์„ ์“ฐ๋Š”๊ฒŒ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Iterators ๋ฐ˜๋ณต์ž

์ง€๊ธˆ๊นŒ์ง€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์‚ฌ์šฉํ•ด๋ดค๋Š”๋ฐ ์‚ฌ์‹ค ์ดํ„ฐ๋ ˆ์ดํŠธ๋Š” ํŠธ๋ ˆ์ดํŠธ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ๋Ÿฌ์ŠคํŠธ์˜ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž…์—๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฏธ๋ฆฌ ๊ตฌํ˜„๋˜์–ด์žˆ์–ด์„œ ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๋งŒ๋“  ํƒ€์ž…์— ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ๊ฒ ์ง€์š”.

์ด๋ฒˆ ์žฅ์—์„œ๋Š” ๋‚ด๊ฐ€ ๋งŒ๋“  ๊ตฌ์กฐ์ฒด ํƒ€์ž…์— ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์†Œ์Šค๋Š” ์ด์ „์— fmt::Display ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณธ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

fn main() {
    let book = Book {
        title: String::from("The Rust Programming Language"),
        author: String::from("Steve Klabnik and Carol Nichols"),
        published: 20230228,
    };

    println!("{}", book);
}

์ด ์˜ˆ์ œ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Book ํƒ€์ž…์— ์ดํ„ฐ๋ ˆ์ดํŠธ๋ฅผ ์ ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์šฐ์„  ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ ์–ด๋–ค ํŠธ๋ ˆ์ดํŠธ์ธ์ง€ ๋Ÿฌ์ŠคํŠธ ๋ฉ”๋‰ด์–ผ์„ ์ฐพ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

pub trait Iterator {
    type Item;

    // Required method
    fn next(&mut self) -> Option<Self::Item>;

    // Provided methods
....skip...
}

https://doc.rust-lang.org/std/iter/trait.Iterator.html

๋ฉ”๋‰ด์–ผ์— ๋”ฐ๋ฅด๋ฉด ํ•„์ˆ˜๋กœ ๊ตฌํ˜„ํ•ด์•ผํ•  next๋ผ๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ 1๊ฐœ์žˆ๊ณ , next๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ 74๊ฐœ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์ด 75๊ฐœ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๋Š” ํŠธ๋ ˆ์ดํŠธ์ž…๋‹ˆ๋‹ค. next๋ฉ”์†Œ๋“œ๋Š” ์ž๊ธฐ ์ž์‹ ์„ mutable ์ฐธ์กฐ๋กœ ๋ฐ›์•„์„œ Option์— ๊ฐ์‹ผ ๊ฒฐ๊ณผ ๊ฐ’ ํ•˜๋‚˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ•ด์•ผํ•  ์ผ์€ Item์ด๋ผ๋Š” ํƒ€์ž…์— ๋ฌด์—‡์„ ์“ธ์ง€ ์ •ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ณดํ†ต์€ ์ž์‹ ์ด ๊ตฌํ˜„ํ•œ ๊ตฌ์กฐ์ฒด๋‚˜ ๊ตฌ์กฐ์ฒด์˜ ์ฐธ์กฐ๊ฐ€ ๋˜๊ฒ ์ง€์š”. ๊ทธ๋ฆฌ๊ณ  ์ฃผ์˜ํ•ด์•ผํ•  ๊ฒƒ์ด ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ ํ˜„์žฌ ๋ช‡๊ฐœ์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ–ˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ๋” ์ด์ƒ ๋ฐ˜ํ™˜ํ•  ๊ฐ’์ด ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ๋“ฑ์˜ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ•ด์•ผ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ ๊ฐ€์ง„ ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜๊ธฐ๋•Œ๋ฌธ์— &mut self๋ผ๋Š” ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ Book ํƒ€์ž…์˜ ๊ฐ์ฒด๋“ค์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ์œ„ํ•œ BookSelf๋ผ๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํƒ€์ž…์„ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

#[derive(Debug)]
struct BookShelf<'a> {
    books: &'a [Book],
}

impl<'a> Iterator for BookShelf<'a> {
    type Item = &'a Book;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((first, remains)) = self.books.split_first() {
            self.books = remains;
            Some(first)
        } else {
            None
        }
    }
}

fn main() {
    let mut book_array = [
        Book {
            title: String::from("The Fellowship of the Ring"),
            author: String::from("J. R. R. Tolkien"),
            published: 19540729,
        },
        Book {
            title: String::from("The Two Towers"),
            author: String::from("J. R. R. Tolkien"),
            published: 19541111,
        },
        Book {
            title: String::from("The Return of the King"),
            author: String::from("J. R. R. Tolkien"),
            published: 19551020,
        },
    ];

    let mut mybooks_iter = BookShelf {
        books: &mut book_array,
    };
    println!("{:?}", mybooks_iter.next());
    println!("{:?}", mybooks_iter.next());
    println!("{:?}", mybooks_iter.next());
    println!("{:?}", mybooks_iter.next());

    let mybooks_for = BookShelf {
        books: &mut book_array,
    };
    for b in mybooks_for {
        println!("{:?}", b);
    }
}
$ cargo run --bin trait_iterator
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
     Running `target/debug/trait_iterator`
Some(Book { title: "The Fellowship of the Ring", author: "J. R. R. Tolkien", published: 19540729 })
Some(Book { title: "The Two Towers", author: "J. R. R. Tolkien", published: 19541111 })
Some(Book { title: "The Return of the King", author: "J. R. R. Tolkien", published: 19551020 })
None
Book { title: "The Fellowship of the Ring", author: "J. R. R. Tolkien", published: 19540729 }
Book { title: "The Two Towers", author: "J. R. R. Tolkien", published: 19541111 }
Book { title: "The Return of the King", author: "J. R. R. Tolkien", published: 19551020 }

์ผ๋‹จ ๊ตฌํ˜„์ด ์–ด๋–ป๊ฒŒํ• ์ง€๋Š” ๋†”๋‘๊ณ  mainํ•จ์ˆ˜์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€๋ถ€ํ„ฐ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

book_array๋ผ๋Š” ์ด๋ฆ„์˜ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ Book ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  mybooks_iter๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ ์ด ๋ณ€์ˆ˜๋Š” BookSelfํƒ€์ž…์ด๊ณ  books๋ผ๋Š” ํ•„๋“œ์— book_array์˜ ์ฐธ์กฐ ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. mybooks_iter๋ผ๋Š” ๋ณ€์ˆ˜๊ฐ€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ mybooks_iter์˜ next()๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋ฐฐ์—ด์— ์ €์žฅ๋œ Book ํƒ€์ž… ๊ฐ์ฒด๋“ค์ด ํ•˜๋‚˜์”ฉ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ for ๋ฃจํ”„์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. mybooks_for๋ผ๋Š” ์ธํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์„œ for ๋ฃจํ”„์— ์‚ฌ์šฉํ•˜๋ฉด next() ๋ฉ”์†Œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœํ•ด์ค๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ BookSelf๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ๋Š”์ง€ ๋ณผ๊นŒ์š”. Bookํƒ€์ž… ๋ฐฐ์—ด์˜ ์ฐธ์กฐ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ๋ฐฐ์—ด์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฒƒ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์—ญํ• ์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ Iterator ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์„ ํ™•์ธํ•ด์•ผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Iterator ๊ตฌํ˜„์„ ๋ณด๋ฉด ๊ฐ€์žฅ ๋จผ์ € ๋ณผ ์ˆ˜ ์žˆ๋Š”๊ฒŒ Item ํƒ€์ž…์€ Book๊ฐ์ฒด์˜ ์ฐธ์กฐ ํฌ์ธํ„ฐ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ next() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ for ๋ฃจํ”„์—์„œ ์‚ฌ์šฉ๋ ๋•Œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์˜ ํƒ€์ž…์ด Book ๊ฐ์ฒด์˜ ์ฐธ์กฐ ํฌ์ธํ„ฐ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ์„ ๋ณด๋ฉด next() ๋ฉ”์†Œ๋“œ์˜ ๊ตฌํ˜„์ด ๋‚˜์˜ต๋‹ˆ๋‹ค. ๋ฉ”์†Œ๋“œ ์ธ์ž๋Š” &mut self๋กœ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  BookSelf ๊ตฌ์กฐ์ฒด mutable ์ฐธ์กฐ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฐ˜ํ™˜๊ฐ’์ธ Option<&Book>์ด ๋˜๊ฒ ์ง€์š”. ๊ตฌํ˜„์€ ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์šฐ์„  ํ˜„์žฌ self.books๋ผ๋Š” ๋ฐฐ์—ด์„ ์ฒซ๋ฒˆ์งธ ๊ฐ์ฒด์™€ ๋‚˜๋จธ์ง€๋กœ ์ชผ๊ฐญ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ž˜ ์ชผ๊ฐœ์ง„๋‹ค๋ฉด ์–ด์จŒ๋“  ๋ฐฐ์—ด์•ˆ์— ๋ฐ์ดํ„ฐ(Book๊ฐ์ฒด์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ)๊ฐ€ 1๊ฐœ ์ด์ƒ ๋“ค์–ด์žˆ๋‹ค๋Š” ๋œป์ด๋ฏ€๋กœ ์ฒซ๋ฒˆ์งธ ๊ฐ์ฒด๋Š” ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” self.books์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ฐฐ์—ด์„ ์ชผ๊ฐœ๋ ค๊ณ ํ–ˆ๋Š”๋ฐ None์ด ๋ฐ˜ํ™˜๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์€ self.books ๋ฐฐ์—ด์— ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋Š” ๋œป์ด๋ฏ€๋กœ None์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์•„๋งˆ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณธ ๊ฒฝํ—˜์ด ์žˆ์œผ์‹œ๋‹ค๋ฉด ์‰ฝ๊ฒŒ ์ต์ˆ™ํ•ด์งˆ ์ˆ˜ ์žˆ์„๊ฑฐ๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ง€ ์ฃผ์˜ํ•ด์•ผํ•  ๊ฒƒ์€ ๋ฐ˜ํ™˜๊ฐ’์€ Option์ด๋ฏ€๋กœ ๋”์ด์ƒ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„๋•Œ None์„ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ์ œ์— impl<'a>์™€ Bookshelf<'a>๊ฐ™์ด ์ƒˆ๋กœ์šด ํ˜•ํƒœ์˜ ๋ฌธ๋ฒ•์ด ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ๋“ค์„ ๋ผ์ดํ”„ํƒ€์ž„(Lifetime)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์— ์ œ๋Œ€๋กœ ์†Œ๊ฐœํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ผ๋‹จ ์ด ์˜ˆ์ œ์™€๊ฐ™์ด ์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ผ์ดํ”„ํƒ€์ž„์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š”, ์ผ๋‹จ ๋ผ์ดํ”„ํƒ€์ž„์„ ์ง€์ •ํ•˜์ง€์•Š๊ณ  ์ฝ”๋”ฉํ•œ ํ›„์— ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๋ผ์ดํ”„ํƒ€์ž„ ์ง€์ •์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋ฒกํ„ฐ์˜ ๊ฐ ์š”์†Œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ณต์ž

์ง€๊ธˆ๊นŒ์ง€๋Š” ๋ฐฐ์—ด์ด๋‚˜ ๋ฒกํ„ฐ์˜ ๊ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•˜๋Š” ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณดํ†ต์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ๋˜๋Š” ์ƒํ™ฉ์ด ๋” ๋งŽ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

fn main() {
    let book_array = [
        Book {
            title: String::from("The Fellowship of the Ring"),
            author: String::from("J. R. R. Tolkien"),
            published: 19540729,
        },
        Book {
            title: String::from("The Two Towers"),
            author: String::from("J. R. R. Tolkien"),
            published: 19541111,
        },
        Book {
            title: String::from("The Return of the King"),
            author: String::from("J. R. R. Tolkien"),
            published: 19551020,
        },
    ];

    for b in book_array.iter() {
        b.author = String::from("John Ronald Reuel Tolkien");
    }

    println!("{:?}", book_array);
}

์ด ์˜ˆ์ œ๋Š” ๋ชจ๋“  ์ฑ…์˜ author ํ•„๋“œ๋ฅผ "John Ronald Reuel Tolkien"์œผ๋กœ ๋ฐ”๊พธ๋ ค๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ๋ฅผ ๋นŒ๋“œํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

$ cargo build --bin trait_iterator_iter_mut
   Compiling pyalgo v0.1.0 (/home/gurugio/pyalgo)
error[E0594]: cannot assign to `b.author`, which is behind a `&` reference
  --> src/main.rs:28:9
   |
27 |     for b in book_array.iter() {
   |              -----------------
   |              |          |
   |              |          help: use mutable method: `iter_mut()`
   |              this iterator yields `&` references
28 |         b.author = String::from("John Ronald Reuel Tolkien");
   |         ^^^^^^^^ `b` is a `&` reference, so the data it refers to cannot be written

For more information about this error, try `rustc --explain E0594`.
error: could not compile `pyalgo` (bin "pyalgo") due to 1 previous error

book_array.iter()๋Š” immutable reference๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ book_array.iter()์—์„œ ๋ฐ˜ํ™˜๋œ ๋ถˆ๋ณ€ ์ฐธ์กฐ๊ฐ€ b์— ์ €์žฅ๋˜๊ณ , b๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์นœ์ ˆํ•˜๊ฒŒ iter() ๋Œ€์‹ ์— iter_mut() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ์•Œ๋ ค์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•œ๊ฐ€์ง€ ๋” ์žŠ์ง€ ๋ง์•„์•ผํ•˜๋Š”๊ฒŒ์žˆ๋Š”๋ฐ book_array ์„ ์–ธ์— mut๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Book {
    title: String,
    author: String,
    published: u32,
}

fn main() {
    let mut book_array = [
        Book {
            title: String::from("The Fellowship of the Ring"),
            author: String::from("J. R. R. Tolkien"),
            published: 19540729,
        },
        Book {
            title: String::from("The Two Towers"),
            author: String::from("J. R. R. Tolkien"),
            published: 19541111,
        },
        Book {
            title: String::from("The Return of the King"),
            author: String::from("J. R. R. Tolkien"),
            published: 19551020,
        },
    ];

    for b in book_array.iter_mut() {
        b.author = String::from("John Ronald Reuel Tolkien");
    }

    println!("{:?}", book_array);
}
$ cargo run --bin trait_iterator_iter_mut
   Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
warning: fields `title` and `published` are never read
 --> src/trait_iterator_iter_mut/main.rs:3:5
  |
2 | struct Book {
  |        ---- fields in this struct
3 |     title: String,
  |     ^^^^^
4 |     author: String,
5 |     published: u32,
  |     ^^^^^^^^^
  |
  = note: `Book` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
  = note: `#[warn(dead_code)]` on by default

warning: `my-rust-book` (bin "trait_iterator_iter_mut") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s
     Running `target/debug/trait_iterator_iter_mut`
[Book { title: "The Fellowship of the Ring", author: "John Ronald Reuel Tolkien", published: 19540729 }, Book { title: "The Two Towers", author: "John Ronald Reuel Tolkien", published: 19541111 }, Book { title: "The Return of the King", author: "John Ronald Reuel Tolkien", published: 19551020 }]

๋ฐฐ์—ด์ด๋‚˜ ๋ฒกํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐ˜๋ณต์ž๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋งŽ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต์€ ๋„คํŠธ์›Œํฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ฑฐ๋‚˜ ๋ณด๋‚ผ๋•Œ, ์ŠคํŠธ๋ฆผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ฌ ๋•Œ ๊ฐ™์ด ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜์ง€์•Š๊ณ  ์กฐ๊ธˆ์”ฉ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์— ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.