Skip to content

Latest commit

ย 

History

History
864 lines (684 loc) ยท 39.6 KB

05_generic_lifetime.md

File metadata and controls

864 lines (684 loc) ยท 39.6 KB

์ œ๋„ค๋ฆญ(Generic) ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์†Œ๊ฐœ

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

// src/generic_struct/main.rs
#[derive(Debug)]
struct Pair<T> {
    first: T,
    second: T,
}

fn add<T>(a: T, b: T) -> T
where
    T: std::ops::Add<Output = T>,
{
    a + b
}

impl<T> std::ops::Add for Pair<T>
where
    T: std::ops::Add<Output = T> + Copy,
{
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self {
            first: self.first + rhs.first,
            second: self.first + rhs.second,
        }
    }
}

fn main() {
    let left_pair: Pair<i32> = Pair {
        first: 5,
        second: 10,
    };

    let right_pair: Pair<i32> = Pair {
        first: 10,
        second: 5,
    };

    let result = add(left_pair, right_pair);
    println!("Sum: {:?}", result);

    let left_pair_u32: Pair<u32> = Pair {
        first: 5,
        second: 10,
    };

    let right_pair_u32: Pair<u32> = Pair {
        first: 10,
        second: 5,
    };

    let result = add(left_pair_u32, right_pair_u32);
    println!("Sum: {:?}", result);
}
$ cargo run --bin generic_struct
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
     Running `target/debug/generic_struct`
Sum: Pair { first: 15, second: 10 }
Sum: Pair { first: 15, second: 10 }

์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋จผ์ € Pair๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Pair<T> {
    first: T,
    second: T,
}

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

C++ ์–ธ์–ด์˜ ์ œ๋„ค๋ฆญ๊ณผ ์™„์ „ํžˆ ๋™์ผํ•œ ๋ฌธ๋ฒ•์„ ๊ฐ€์ง€๊ณ ์žˆ๊ณ , ํŒŒ์ด์„ ๋“ฑ์˜ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค์—์„œ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ๋„ ๊ฑฐ์˜ ๋™์ผํ•˜๋ฏ€๋กœ, ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ ์ œ๋„ค๋ฆญ์„ ์ ‘ํ•ด๋ณด์‹  ๋ถ„๋“ค์€ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ์€ ์ผ๋ฐ˜ ํ•จ์ˆ˜ add์ž…๋‹ˆ๋‹ค.

fn add<T>(a: T, b: T) -> T
where
    T: std::ops::Add<Output = T>,
{
    a + b
}

ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” T์ž…๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ T์—๋Š” ๋‹ค์–‘ํ•œ ํƒ€์ž…๋“ค์ด ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์ž๊ฐ€ ๋‘๊ฐœ ์žˆ๋Š”๋ฐ ๋‘ ์ธ์ž๊ฐ€ ๋ฐ˜๋“œ์‹œ ๊ฐ™์€ ํƒ€์ž…์ด์–ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ํƒ€์ž…์˜ ์ธ์ž๋ฅผ ๋‘๊ฐœ ๋ฐ›์•„์„œ ๋‘ ์ธ์ž๋ฅผ ํ•ฉํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋Ÿฌ์ŠคํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์ด ์žˆ๋Š”๋ฐ, ๋Ÿฌ์ŠคํŠธ์˜ ์ œ๋„ค๋ฆญ ํ•จ์ˆ˜์—๋Š” ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์–ด๋–ค ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š”์ง€๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

where
    T: std::ops::Add<Output = T>,

์ด๋ ‡๊ฒŒ where์ ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉด Tํƒ€์ž…์€ std::ops::AddํŠธ๋ ˆ์ดํŠธ๋ฅผ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์–ด์•ผํ•˜๋ฉฐ Add ํŠธ๋ ˆ์ดํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” Outputํƒ€์ž…์€ T๊ฐ€ ๋˜์–ด์•ผํ•œ๋‹ค๋Š” ์ œ์•ฝ์กฐ๊ฑด์„ ๊ฑธ๊ฒŒ๋ฉ๋‹ˆ๋‹ค. where๋ฅผ ์•ˆ์“ฐ๊ณ  ์•„๋ž˜์™€๊ฐ™์ด ํ•œ์ค„์— ํƒ€์ž…์„ ๋‹ค ์จ์ค˜๋„ ๋ฉ๋‹ˆ๋‹ค. ์ €๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์— ๋Œ€ํ•ด์„œ ๊ฐ•์กฐ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ where๋ฅผ ์จ์„œ ๋ถ„๋ฆฌํ•ด์„œ ํ‘œ๊ธฐ๋ฅผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

์•„๋ž˜์™€๊ฐ™์ด ์ •์ˆ˜๋‚˜ ์‹ค์ˆ˜๋ฅผ addํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ •์ˆ˜๋‚˜ ์‹ค์ˆ˜ ํƒ€์ž…์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์ด๋ฏธ std::ops::Add ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

    let result = add(3.14, 1.618);
    println!("Sum: {}", result); // Prints "Sum: 4.758"

์ •์ˆ˜๋‚˜ ์‹ค์ˆ˜๊ฐ€ std::ops::Add ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์ด๋ฏธ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— add ํ•จ์ˆ˜์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๊ทธ๋Ÿผ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Pair๋ผ๋Š” ํƒ€์ž…๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ std::ops::Add ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด addํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. Pairํƒ€์ž…์„ ์œ„ํ•œ std::ops::Add ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์„ ํ•ด๋ณผ๊นŒ์š”.

impl<T> std::ops::Add for Pair<T>
where
    T: std::ops::Add<Output = T> + Copy,
{
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self {
            first: self.first + rhs.first,
            second: self.first + rhs.second,
        }
    }
}

์ด์ „์— ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์†Œ๊ฐœํ•  ๋•Œ ๊ตฌํ˜„ํ•ด๋ณธ ๊ฒƒ๊ณผ ์กฐ๊ธˆ ๋” ๋ณต์žกํ•ด์กŒ์Šต๋‹ˆ๋‹ค. ๊ฐ ์ฐจ์ด์ ๋“ค์„ ํ•˜๋‚˜์”ฉ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๋จผ์ € Pair ํƒ€์ž…์ด ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— Pairํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์—๋„ ๋˜‘๊ฐ™์ด <T>๋ผ๋Š” ํƒ€์ž… ์ง€์ •์ด ์ถ”๊ฐ€(์ด๋ ‡๊ฒŒ ์ œ๋„ค๋ฆญ์—์„œ ํƒ€์ž…์ด ์ง€์ •๋˜๋Š” ๊ฒƒ์„ ๋ฐ”์ธ๋”ฉ์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค)๋˜์—ˆ์Šต๋‹ˆ๋‹ค. impl<T>์™€ Pair<T> ์ด๋ ‡๊ฒŒ 2๊ตฐ๋ฐ์— ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

impl<T> std::ops::Add for Pair<T>

addํ•จ์ˆ˜์—์„œ Tํƒ€์ž…์ด std::ops::Add ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์ด ๋˜์–ด์žˆ์–ด์•ผํ•œ๋‹ค๋Š” ์ œํ•œ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ Pair๋ฅผ ์œ„ํ•œ ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์—์„œ๋„ ์•„๋ž˜์™€๊ฐ™์ด Tํƒ€์ž…์ด std::ops::Add ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค๋Š” ์ œ์•ฝ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

where
    T: std::ops::Add<Output = T> + Copy,

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

error[E0382]: use of moved value: `self.first`
  --> src/main.rs:15:21
   |
14 |             first: self.first + rhs.first,
   |                    ---------------------- `self.first` moved due to usage in operator
15 |             second: self.first + rhs.second,
   |                     ^^^^^^^^^^ value used here after move
   |
note: calling this operator moves the left-hand side
  --> /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/arith.rs:92:12
   |
92 |     fn add(self, rhs: Rhs) -> Self::Output;
   |            ^^^^
   = note: move occurs because `self.first` has type `T`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0382`.

๊ณ ๋ง™๊ฒŒ๋„ Copy ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ผ๊ณ  ์•Œ๋ ค์ฃผ๊ณ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋‹จ๊ณ„์—์„œ ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋œ๋‹ค๊ณ ํ•ด๋„ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์•Œ๋ ค์ฃผ๋Š”๋Œ€๋กœ Copy๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์ผ๋‹จ ๋นŒ๋“œ๊ฐ€๋˜๋„๋ก ๋งŒ๋“ค๊ณ  ์ฒœ์ฒœํžˆ ์ดํ•ดํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค.

Copy ํŠธ๋ ˆ์ดํŠธ๋Š” Marker ํŠธ๋ ˆ์ดํŠธ๋กœ ์†Œ์œ ๊ถŒ์ด ์ด๋™ํ•  ๋•Œ ์ด ํƒ€์ž…์ด ๋น„ํŠธ๋‹จ์œ„๋กœ ๋ณต์‚ฌํ•˜๋ฉด ๊ฐ’์ด ์ด๋™๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ํ‘œ์‹œ๋ฅผ ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ณดํ†ต Clone ํŠธ๋ ˆ์ดํŠธ๋Š” ๊ฐ์ฒด๋„ ๊ฐ™์ด ๋ณต์‚ฌํ•˜๋Š” Deep copy๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ Copy๋Š” ๋น„ํŠธ๋‹จ์œ„ ๋ณต์‚ฌ๋งŒ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ํฌ์ธํ„ฐ ๊ฐ’๋งŒ ๋ณต์‚ฌ๋˜๊ณ  ๊ฐ์ฒด๋Š” ๋ณต์‚ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํฌ์ธํ„ฐ์™ธ์—๋„ i32๊ฐ™์€ ๊ธฐ๋ณธ ํƒ€์ž…์—๋Š” Copy ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๊ตฌํ˜„๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์ฝ”๋“œ์—์„œ self๊ฐ€ ์ธ์ž๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ ๋น„ํŠธ๋‹จ์œ„๋กœ ๋ณต์‚ฌ๋˜์–ด์„œ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

std::ops::Add ํŠธ๋ ˆ์ดํŠธ์˜ ๊ตฌํ˜„์„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

{
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self {
            first: self.first + rhs.first,
            second: self.first + rhs.second,
        }
    }
}

๋‘ ํƒ€์ž…์„ ๋”ํ•œ ๊ฒฐ๊ณผ๋ฌผ์€ ๊ฐ™์€ ํƒ€์ž…์ด ๋˜๋Š”๊ฒŒ ๋ณดํ†ต์ด๊ฒ ์ง€์š”. ๊ทธ๋ž˜์„œ Output์„ Self ํƒ€์ž…์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  add๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. add ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’์€ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์ง„ Selfํƒ€์ž…์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. first์™€ second ํ•„๋“œ๋ฅผ ๊ฐ๊ฐ ๊ณ„์‚ฐํ•ด์„œ ์ƒˆ๋กœ์šด Self ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ตœ์ข…์ ์œผ๋กœ mainํ•จ์ˆ˜์—์„œ Pairํƒ€์ž…์˜ ๋‘ ๋ณ€์ˆ˜, left_pair์™€ right_pair๋ฅผ addํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

fn main() {
    let left_pair: Pair<i32> = Pair {
        first: 5,
        second: 10,
    };

    let right_pair: Pair<i32> = Pair {
        first: 10,
        second: 5,
    };

    let result = add(left_pair, right_pair);
    println!("Sum: {:?}", result);
...

์—ฌ๊ธฐ์—์„œ result์˜ ํƒ€์ž…์ด ์ƒ๋žต๋˜์—ˆ์ง€๋งŒ Pair<i32>ํƒ€์ž…์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

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

ํŠธ๋ ˆ์ดํŠธ์— ์ œ๋„ค๋ฆญ ์‚ฌ์šฉํ•˜๊ธฐ

๊ตฌ์กฐ์ฒด ํƒ€์ž…์— ์ ์šฉ๋œ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•ด๋ดค์œผ๋‹ˆ๊นŒ ์ด๋ฒˆ์—๋Š” ํŠธ๋ ˆ์ดํŠธ์— ์ ์šฉ๋œ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” ์ด์ „์— ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์„ค๋ช…ํ•˜๋ฉด์„œ ์‚ฌ์šฉํ–ˆ๋˜ Printable ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„ ์˜ˆ์ œ๋ฅผ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฐ”๊พผ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

// src/generic_trait/main.rs
trait Printable<AGE> {
    fn print(&self);
    fn get_age(&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<u32> for Person {
    fn print(&self) {
        println!("Name: {}, {} years old", self.name, self.age);
    }
    fn get_age(&self) -> u32 {
        self.age
    }
}

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

fn main() {
    let person: Person = Person::new("Alice", 22);
    print_info(&person);
}
$ cargo run --bin generic_trait
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/generic_trait`
Name: Alice, 22 years old

ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์„ค๋ช…ํ•˜๋ฉด์„œ Printable ํŠธ๋ ˆ์ดํŠธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์—ฐ๊ด€ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์„ค๋ช…ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

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

์ œ๋„ค๋ฆญ์„ ์•ˆ๋‹ค๋ฉด ์ด๊ฒƒ์„ ์•„๋ž˜์™€๊ฐ™์ด ์ œ๋„ค๋ฆญ์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

trait Printable<AGE> {
    fn print(&self);
    fn get_age(&self) -> AGE;
}

๊ทธ๋ฆฌ๊ณ  Printable์„ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•  ๋•Œ๋„ โ€œAge=u32โ€๋ผ๋Š” ์—ฐ๊ด€ ํƒ€์ž… ์ง€์ •์„ ์“ธํ•„์š”์—†์ด ์ œ๋„ค๋ฆญ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

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

print_info์— ์ „๋‹ฌํ•  ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋„ <u32>์ด๋ผ๋Š” ํƒ€์ž… ๋ฐ”์ธ๋”ฉ์„ ๊ฐ€์ง€๊ณ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด์™€ ์ œ๋„ค๋ฆญ์ด ๊ฒฐํ•ฉ๋œ๊ฒŒ ํ•œ๋ฒˆ์— ๋ˆˆ์— ๋“ค์–ด์˜ค์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ 3๋‹จ๊ณ„๋กœ ์ƒ๊ฐํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

  1. print_info์— ์ „๋‹ฌ๋˜๋Š” ์ธ์ž๋Š” ํ•˜๋‚˜์˜ ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ, ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  2. print_info์— ์ „๋‹ฌ๋˜๋Š” ํƒ€์ž…์€ Printable์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ํƒ€์ž…์˜ ๋ ˆํผ๋Ÿฐ์Šค์ด๋‹ค.
  3. Printable์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๋ฐ˜๋“œ์‹œ u32 ํƒ€์ž…์„ ์œ„ํ•ด ๊ตฌํ˜„๋˜์–ด์•ผํ•œ๋‹ค.

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

ํŠธ๋ ˆ์ดํŠธ์™€ ๊ตฌ์กฐ์ฒด ๋ชจ๋‘ ์ œ๋„ค๋ฆญ ์‚ฌ์šฉํ•˜๊ธฐ

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŠธ๋ ˆ์ดํŠธ์—๋„ ์ œ๋„ค๋ฆญ์ด ์‚ฌ์šฉ๋˜๊ณ , ๊ตฌ์กฐ์ฒด์—๋„ ์ œ๋„ค๋ฆญ์ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์‹ค๋ฌด์—์„œ ๋” ์ผ๋ฐ˜์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// src/generic_trait_struct/main.rs
trait Printable<AGE> {
    fn print(&self);
    fn get_age(&self) -> AGE;
}

#[derive(Debug)]
struct Address {
    post: u32,
    city: String,
}

impl Default for Address {
    fn default() -> Self {
        Address {
            post: 0,
            city: "Unknown".to_string(),
        }
    }
}

struct Person<ADDR> {
    name: String,
    age: u32,
    location: ADDR,
}

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

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

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

fn main() {
    let alice: Person<Address> = Person::new("Alice", 22, Address::default());
    print_info(&alice);
    println!("Alice is at : {:?}", alice.location);

    let bruce: Person<String> = Person::new("Bruce", 33, "NewYork".to_string());
    println!("Bruce is at : {:?}", bruce.location);
}
$ cargo run --bin generic_trait_struct
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s
     Running `target/debug/generic_trait_struct`
Name: Alice, 22 years old
Alice is at : Address { post: 0, city: "Unknown" }
Bruce is at : "NewYork"

์˜ˆ์ œ๊ฐ€ ๋ณต์žกํ•ด๋ณด์ด์ง€๋งŒ ์ด 2๊ฐ€์ง€์˜ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์“ฐ๊ณ ์žˆ๊ณ , ๊ฐ๊ฐ์ด ๋ฌด์—‡์„ ์œ„ํ•œ ํƒ€์ž…์ธ์ง€๋ฅผ ๊ธฐ์–ตํ•˜๋ฉด์„œ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ํŠธ๋ ˆ์ดํŠธ Printable์˜ AGE ํƒ€์ž… ํŒŒ๋ผ์ดํ„ฐ: ๋‚˜์ด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค.
  2. ๊ตฌ์กฐ์ฒด Person์˜ ADDR ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ: ์ฃผ์†Œ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

์•ฝ๊ฐ„์˜ ์š”๋ น์ด ์žˆ๋Š”๋ฐ Person ๊ตฌ์กฐ์ฒด์˜ ํƒ€์ž…์„ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ํ•ญ์ƒ Person<ADDR>๋กœ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ธฐ์–ตํ•˜๋ฉด ํŽธํ•ฉ๋‹ˆ๋‹ค. Printable ํŠธ๋ ˆ์ดํŠธ์˜ ๊ตฌํ˜„ ์ฝ”๋“œ์—์„œ๋„ Person<ADDR>๊ณผ ๊ฐ™์ด ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ํ•ญ์ƒ ์จ์ค˜์•ผํ•œ๋‹ค๋Š”๊ฑธ ์ฃผ์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

impl<ADDR> Person<ADDR> {
...
impl<ADDR> Printable<u32> for Person<ADDR> {
...

๊ทธ๋Ÿผ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ชผ๊ฐœ์„œ ํ•˜๋‚˜์”ฉ ์ฝ์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋จผ์ €๋Š” Printable์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

trait Printable<AGE> {
    fn print(&self);
    fn get_age(&self) -> AGE;
}

Printable์ด๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์žˆ๋Š”๋ฐ ์•„์ง ๊ตฌํ˜„์€ ์•ˆ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ๊ทธ๋Ÿฐ ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์žˆ๊ณ , print์™€ get_age๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋“ค์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์„ ์–ธํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. get_age๋Š” AGE๋ผ๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค. ๋‚˜์ด๋Š” ๋ณดํ†ต ์ •์ˆ˜๊ฐ’์ด ๋˜๊ฒ ์ง€๋งŒ, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ๋„ ์žˆ๋‚˜๋ด…๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด๋‹ˆ ๋‚˜์ค‘์— Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ์—์„œ AGE ํƒ€์ž…์„ ๋ฌด์—‡์œผ๋กœํ• ์ง€ ์ •ํ•˜๊ฒŒ๋ ๊ฑฐ๋ผ๋Š” ์˜ˆ์ƒ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ์€ Address๋ผ๋Š” ๊ตฌ์กฐ์ฒด ํƒ€์ž…์„ ๋งŒ๋“ค๊ณ ์žˆ์Šต๋‹ˆ๋‹ค.

#[derive(Debug)]
struct Address {
    post: u32,
    city: String,
}

impl Default for Address {
    fn default() -> Self {
        Address {
            post: 0,
            city: "Unknown".to_string(),
        }
    }
}

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

๊ทธ ๋‹ค์Œ์€ Person์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

struct Person<ADDR> {
    name: String,
    age: u32,
    location: ADDR,
}

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

์‚ฌ๋žŒ์˜ ์ด๋ฆ„, ๋‚˜์ด, ์œ„์น˜๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค. ์œ„์น˜๊ฐ€ ๊ผญ ์ง‘ ์ฃผ์†Œ๊ฐ™์€ ๋ฌธ์ž์—ด์ด ๋  ํ•„์š”๋Š” ์—†์œผ๋ฏ€๋กœ ADDR์ด๋ผ๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์‚ฌ์šฉํ•ด์คฌ์Šต๋‹ˆ๋‹ค. ์šฐํŽธ๋ฒˆํ˜ธ๋„ ๋  ์ˆ˜ ์žˆ๊ณ , ์ขŒํ‘œ๋„ ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ Post๋‚˜ Coordinates๊ฐ™์ด ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ฒ ๋„ค์š”. ๊ทธ๋ž˜์„œ ์ œ๋„ค๋ฆญ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค์—ˆ๋‚˜๋ด…๋‹ˆ๋‹ค. impl<ADDR> Person<ADDR>๊ณผ ๊ฐ™์ด ADDR์ด๋ผ๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์–ด๋””์— ์จ์ค˜์•ผ๋˜๋Š”์ง€๋ฅผ ์ž˜ ๋ด์ฃผ์„ธ์š”.

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

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

์ฒซ์ค„์€ ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์„ ์„ ์–ธํ•˜๋Š” ์ฝ”๋“œ์ธ๋ฐ 2๊ฐœ์˜ ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด ๋™์‹œ์— ๋‚˜์˜ค๋ฏ€๋กœ ๋ˆˆ์— ์ž˜ ์•ˆ๋“ค์–ด์˜ต๋‹ˆ๋‹ค. ํ•œ๊ธ€๋กœ ๋‹ค์‹œ ์จ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

impl<๊ตฌ์กฐ์ฒด์˜ ์ œ๋„ค๋ฆญ ํƒ€์ž…> ํŠธ๋ ˆ์ดํŠธ<ํŠธ๋ ˆ์ดํŠธ์˜ ์ œ๋„ค๋ฆญ ํƒ€์ž…> for ๊ตฌ์กฐ์ฒด์ด๋ฆ„<๊ตฌ์กฐ์ฒด์˜ ์ œ๋„ค๋ฆญ ํƒ€์ž…> {

Printable ํŠธ๋ ˆ์ดํŠธ๊ฐ€ u32ํƒ€์ž…์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” get_age๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ u32 ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ print_info์— ์ „๋‹ฌ๋˜๋Š” ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๊ฐ€ Printable<u32> ํƒ€์ž…์ด ๋ฉ๋‹ˆ๋‹ค.

fn print_info(item: &dyn Printable<u32>) {

Printable<i32>๋‚˜ Printable<String>๋“ฑ๋“ฑ ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด ๋‹ค๋ฅธ Printable ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ํƒ€์ž…๋“ค์€ print_info์— ์ „๋‹ฌ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜ค์ง Printable<u32>๋งŒ์ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

ํŠธ๋ ˆ์ดํŠธ์™€ ์ œ๋„ค๋ฆญ์„ ์ฒ˜์Œ ์ ‘ํ•˜์‹œ๋Š” ๋ถ„๋“ค์„ ์œ„ํ•œ ์•ˆ๋‚ด

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

  1. ์ผ๋‹จ์€ ํŠธ๋ ˆ์ดํŠธ์™€ ์ œ๋„ค๋ฆญ์„ ์ƒ๊ฐํ•˜์ง€์•Š๊ณ  ๋‹น์žฅ ๋™์ž‘ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ์ต์ˆ™ํ•˜์ง€์•Š์€ ๊ฐœ๋…์„ ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ๊ฐœ๋ฐœ๋‹จ๊ณ„์—์„œ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฌด๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ผ๋‹จ์€ ๋™์ž‘์—๋งŒ ์ง‘์ค‘ํ•ด์„œ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์‹ค ํ”„๋กœํ† ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๋‹จ๊ณ„์—์„œ ์•„์ฃผ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋งŒ์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ํŠธ๋ ˆ์ดํŠธ์™€ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•  ํ•„์š”๋„ ์—†์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์†Œํ•œ์˜ ํ•„์ˆ˜ ๊ธฐ๋Šฅ๋งŒ์„ ์ž˜ ๋™์ž‘ํ•˜๋„๋ก ๋งŒ๋“œ๋Š”๋ฐ ์ง‘์ค‘ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ•„์ˆ˜ ๊ธฐ๋Šฅ์ด๋‚˜ ์†Œํ”„ํŠธ์›จ์–ด์˜ ๋ผˆ๋Œ€๊ฐ€ ๋˜๋Š” ๋ชจ๋“ˆ๋“ค๋งŒ ๊ตฌํ˜„ํ•œ ํ›„์—๋Š” ์ ์ฐจ ์†Œํ”„ํŠธ์›จ์–ด์˜ ๊ทœ๋ชจ๋ฅผ ๋Š˜๋ ค๋‚˜๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์ข€๋” ๊ฐ ๋ชจ๋“ˆ์„ ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ์ž˜ ์ •๋ฆฌ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ฒŒ ๋‹ค๋“ฌ์–ด๋‚˜๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ •๋„ ๋‹จ๊ณ„๊ฐ€๋˜๋ฉด ์กฐ๊ธˆ์”ฉ ๋ฐ˜๋ณต๋˜๋Š” ํŒจํ„ด๋“ค์ด ์ƒ๊ฒจ๋‚˜๊ฒŒ๋˜๊ณ  ํŠธ๋ ˆ์ดํŠธ๋‚˜ ์ œ๋„ค๋ฆญ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ๋ฉ๋‹ˆ๋‹ค.
  3. ๊ฐ์ฒด๋“ค๊ฐ„์— ๋ฐ˜๋ณต๋˜๋Š” ํŠน์„ฑ์ด ์žˆ๊ฑฐ๋‚˜ ๊ณตํ†ต์ ์ธ ๋™์ž‘์€ ํŠธ๋ ˆ์ดํŠธ๋กœ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํŠธ๋ ˆ์ดํŠธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ‘œ์ค€ํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์˜ค์ง ํ•ด๋‹น ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋“ค๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ƒ๊ธด๋‹ค๋ฉด, ์ถ”ํ›„์— ๋ณธ์ธ์ด ์•„๋‹Œ ๋ˆ„๊ฐ€ ๊ฐœ๋ฐœ์— ์ฐธ์—ฌํ•œ๋‹ค๊ณ ํ•ด๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค.
  4. ๊ตฌ์กฐ์ฒด๋‚˜ ์—ด๊ฑฐํ˜• ํƒ€์ž…์— ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์„ ํ•ญ์ƒ ๊ฐ™์ด ์ƒ๊ฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ฒด์— ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์ถ”๊ฐ€ํ–ˆ์„ ๋•Œ ์ด ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด u32, char๊ฐ™์€ ์ผ๋ฐ˜ ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ๋˜ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ƒ๊ฐํ•˜๋ฉด์„œ, ๊ทธ๋ ‡๋‹ค๋ฉด ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด ์–ด๋–ค ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ๋งŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ๊ณ ๋ คํ•ด์„œ ํŠธ๋ ˆ์ดํŠธ ๊ตฌํ˜„์— where๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ ์ฐจ where์— Copy๋“ฑ์˜ ๋งˆ์ปค ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ์—†์–ด์„œ ๋นŒ๋“œ๊ฐ€ ์•ˆ๋˜๋Š” ๊ฒƒ์„ ๊ฒฝํ—˜ํ•˜์‹ค ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋งˆ์ปค ํŠธ๋ ˆ์ดํŠธ์— ์–ด๋–ค ๊ฒƒ๋“ค์ด ์žˆ๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๋“ฑ์„ ์กฐ๊ธˆ์”ฉ ๊ฒฝํ—˜ํ•˜๋ฉด์„œ ํŠธ๋ ˆ์ดํŠธ์™€ ์ œ๋„ค๋ฆญ์— ๋Œ€ํ•ด์„œ ๋” ์ž˜ ์ดํ•ดํ•˜๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  5. ๋‹น์—ฐํžˆ ๊ฐ์ฒด์ง€ํ–ฅ์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ์žˆ๋‹ค๋ฉด ๋” ๋นจ๋ฆฌ ์ต์ˆ™ํ•ด์ง€์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์Šค์ผˆ๋“ฑ ์ˆœ์ˆ˜ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด๋ฟ ์•„๋‹ˆ๋ผ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์— ๋Œ€ํ•œ ์ฑ…๋“ค๋„ ์ฝ์–ด๋ณด์„ธ์š”. ๊ทธ๋ฆฌ๊ณ  ํ•จ์ˆ˜ํ˜• ์–ธ์–ด์™€ ์„ค๊ณ„์— ๋Œ€ํ•ด์„œ๋„ ๊ฒฝํ—˜ํ•ด๋ณด๋ฉด ๋Ÿฌ์ŠคํŠธ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์ €๋Š” Scala์™€ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•œ ์˜จ๋ผ์ธ ์ˆ˜์—…์„ ๋“ฃ๊ณ , Structure and Interpretation of Computer Programs๋ผ๋Š” Scheme์–ธ์–ด์— ๊ด€ํ•œ ์ฑ…์˜ ์—ฐ์Šต๋ฌธ์ œ๋ฅผ ํ’€์–ด๋ณด๋ฉด์„œ, ํ•จ์ˆ˜ํ˜• ์–ธ์–ด์™€ ์„ค๊ณ„์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

ํŠธ๋ ˆ์ดํŠธ์™€ ์ œ๋„ค๋ฆญ์„ ์ด์šฉํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์‹ค์Šต

๋Ÿฌ์ŠคํŠธ์˜ Result, Option์„ ๋ฐฐ์šฐ๋ฉด ์ฒ˜์Œ์—๋Š” ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

fn check_command(cmd: &str) -> Result<usize, String> {
  match cmd {
    "good" => Ok(0),
    "unsupported" => Err("Unsupported command".to_owned()),
    "bad" => Err("Bad command".to_owned()),
    _ => Err("Wierd command".to_owned()),
  }
}

fn handle_command(cmd: &str) -> Result<usize, String> {
  // use unwrap
  let passed = check_command(cmd).unwrap();
  println!("first check passed: status={}", passed);

  // check Result
  let failed = check_command(cmd);
  if failed.is_ok() {
    println!("Second check passed: status={}", failed.unwrap());
  } else if failed.is_err() {
    println!("Second check failed: status={:?}", failed);
  }

  // use pattern
  match check_command(cmd) {
    Ok(s) => println!("Third check passed:{}", s),
    Err(s) => println!("Error={}", s),
  }

  Ok(0)
}

fn main() {
  let status = handle_command("good");
  if status.is_ok() {
    println!("Everything is fine");
  } else {
    println!("I don't feel good");
  }
}

์˜ˆ์ œ์— ์žˆ๋Š” check_commandํ•จ์ˆ˜์™€ handle_command ํ•จ์ˆ˜๋Š” Result๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰์— ์„ฑ๊ณตํ–ˆ์„๋•Œ์˜ ๋ฐ˜ํ™˜๊ฐ’์€ usizeํƒ€์ž…์ด๊ณ , ์‹คํŒจํ–ˆ์„ ๋•Œ๋Š” Stringํƒ€์ž…์œผ๋กœ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ Resultํƒ€์ž…์œผ๋กœ ์–ป์€ ๋ฐ˜ํ™˜๊ฐ’์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ฃผ๋กœ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š”๋ฐ

  1. unwrap ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
  2. is_ok, is_err๋“ฑ ๋ฐ˜ํ™˜๊ฐ’์„ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
  3. match๋ฅผ ์ด์šฉํ•œ ํŒจํ„ด ๋งค์นญ์œผ๋กœ ๋ฐ˜ํ™˜๊ฐ’์„ ๊บผ๋‚ด์„œ ํ™•์ธ

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

๊ทธ๋ฆฌ๊ณ  ์–ด์จŒ๋“  ๋ฐ˜ํ™˜๊ฐ’์ด ์—๋Ÿฌ์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ํ™•์ธํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— is_ok, is_err ๋“ฑ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ๋งคํ„ด ๋งค์นญ์„ ์‚ฌ์šฉํ•ด์„œ Result์•ˆ์— ์žˆ๋Š” ๊ฐ’์„ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ด๋Ÿฌ๋ฉด check_command์—์„œ ์ด๋ฏธ ํ•œ๋ฒˆ ์ฒดํฌํ•œ ์—๋Ÿฌ๋ฅผ handle_command ํ•จ์ˆ˜์—์„œ ๋˜ ๋‹ค์‹œ ์ฒดํฌํ•˜๋Š” ๊ผด์ž…๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ์—๋Ÿฌ ์ฒดํฌ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„์ง‘๋‹ˆ๋‹ค. handle_command ํ•จ์ˆ˜๋Š” ์—๋Ÿฌ๋ฅผ ์ฒดํฌํ•˜๋ ค๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ, ์ •์ƒ์ ์ธ ์ƒํ™ฉ์—์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š”๊ฒŒ ์ฃผ ๋ชฉํ‘œ์ธ ํ•จ์ˆ˜์ด๊ณ , ๋งŒ์•ฝ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ์œผ๋ฉด ๋ฐ”๋กœ ์—๋Ÿฌ ๊ฐ’์„ ์ƒ์œ„ ํ•จ์ˆ˜๋กœ ๋ฐ˜ํ™˜ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์ด๋ ‡๊ฒŒ ์—๋Ÿฌ ์ฒดํฌ๋ฅผ ์ผ์ผ์ด ๋‹ค์‹œ ํ•  ํ•„์š”๊ฐ€ ์—†์ง€์š”.

์กฐ๊ธˆ๋” ๋Ÿฌ์ŠคํŠธ ์–ธ์–ด๋‹ค์šด(์˜์–ด๋กœ๋Š” Rusty๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ง์—ญ์„ ํ•˜๋ฉด ๋…น์ด ์Šฌ์—ˆ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.) ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ผ๋ฐ˜์ ์ธ ๊ฒƒ์ด๊ณ  ๋ชจ๋“  ํ”„๋กœ์ ํŠธ๊ฐ€ ์ด๋ ‡๊ฒŒ ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋Ÿฌ์ŠคํŠธ ์–ธ์–ด์—์„œ ๊ถŒ์žฅํ•˜๋Š” ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์„ ํ•œ๋ฒˆ ๋ณด๊ณ ๋‚˜๋ฉด ๋Ÿฌ์ŠคํŠธ๊ฐ€ ์ถ”๊ตฌํ•˜๋Š” ์—๋Ÿฌ์— ๋Œ€ํ•œ ์ •์ฑ…๊ณผ Result/Option ๋“ฑ์˜ ์„ค๊ณ„ ์ฒ ํ•™์„ ๋” ์ž˜ ์ดํ•ดํ•˜์‹ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฒซ๋ฒˆ์งธ๋กœ ๋‚ด ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์—๋Ÿฌ ํƒ€์ž…์„ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  Resultํƒ€์ž…์„ ์žฌ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉํ•  ๋ชจ๋“  Result ํƒ€์ž…์—์„œ ์—๋Ÿฌ๋Š” MyError๋ผ๋Š” ํƒ€์ž…๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

#[derive(Debug, PartialEq)]
pub enum MyError {
    UnsupportedCommand,
    WrongInput(String),
    UnknownValue {
        name: String,
        expected: String,
        found: String,
    },
    // Add more error cases
}

pub type Result<T, E = MyError> = std::result::Result<T, E>;

๋จผ์ € ๋‚ด ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ๋“ค์„ ์ƒ๊ฐํ•ด์„œ ๊ฐ ์—๋Ÿฌ๋งˆ๋‹ค ๋ณ„๋„์˜ ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ , ๊ฐ ํƒ€์ž…๋งˆ๋‹ค ์–ด๋–ค ์ •๋ณด๋ฅผ ๋„ฃ์–ด์ค„ ๊ฒƒ์ธ์ง€๋ฅผ ์ƒ๊ฐํ•ด์„œ MyError๋ผ๋Š” ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์ œ์—์„œ๋Š” command์ฒ˜๋ฆฌ์— ์žˆ์–ด์„œ 3๊ฐ€์ง€ ๊ฒฝ์šฐ์˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ๊ฐ์˜ ๊ฒฝ์šฐ์— ๋”ฐ๋ฅธ ์—๋Ÿฌ ๊ฐ’์„ ๋งŒ๋“ค์–ด์คฌ์Šต๋‹ˆ๋‹ค.

  • UnsupportedCommand: ๋ช…๋ น์–ด๊ฐ€ ์ง€์›๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ์ถ”๊ฐ€์ ์ธ ๋ฐ์ดํ„ฐ๋Š” ์—†๋Š” ์—๋Ÿฌ ๊ฐ’์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.
  • WrongInput(String): ์ž˜๋ชป๋œ ์ž…๋ ฅ์˜ ๊ฒฝ์šฐ ์–ด๋–ค ์ž…๋ ฅ์ด ์ž˜๋ชป๋˜์—ˆ๋Š”์ง€๋ฅผ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋กœ ์•Œ๋ ค์ฃผ๊ธฐ ์œ„ํ•ด String ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ์—๋Ÿฌ ๊ฐ’์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.
  • UnknownValue{โ€ฆ}: ์ด ์—๋Ÿฌ๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์ข€ ๋” ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์กฐ์ฒด์™€ ๊ฐ™์ด ์—ฌ๋Ÿฌ ํ•„๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ์—๋Ÿฌ ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

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

๋‚ด๊ฐ€ ๋งŒ๋“  ํ•จ์ˆ˜์—์„œ๋Š” MyError๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์–ป๊ฒŒ๋˜๋Š” ๋‹ค๋ฅธ ํƒ€์ž…์˜ ์—๋Ÿฌ๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผํ• ๊นŒ์š”? ๊ทธ๋Ÿด๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์—๋Ÿฌ์˜ ํƒ€์ž…์„ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ƒ์œ„ ํ•จ์ˆ˜๋Š” MyError ํƒ€์ž…๋งŒ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    let mut file = match File::open(&path) {
        Err(why) => MyError::WrongInput(format!("Cannot open the file {}, because {}", path, why),
        Ok(file) => file,
    };

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

// fn check_command(cmd: &str) -> Result<usize, String> {
fn check_command(cmd: &str) -> Result<usize> {
    match cmd {
        "good" => Ok(0),
        "unsupported" => Err(MyError::UnsupportedCommand),
        "bad" => Err(MyError::WrongInput(format!(
            "Cannot handle the command:{}",
            cmd
        ))),
        _ => Err(MyError::UnknownValue {
            name: "Wierd Command Error".to_owned(),
            expected: "good".to_owned(),
            found: cmd.to_owned(),
        }),
    }
}

๋‚ด ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ์—๋Ÿฌ ํƒ€์ž…์„ ๋งŒ๋“ค๊ณ , ์ด ์—๋Ÿฌ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  Result๋ฅผ ์žฌ์ •์˜ํ•˜๊ณ  ๋‚˜๋ฉด check_commandํ•จ์ˆ˜์™€ ๊ฐ™์ด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ด ๋‹จ์ˆœํ•ด์ง‘๋‹ˆ๋‹ค. ์›๋ž˜๋Š” Result<usize, String>๊ณผ ๊ฐ™์ด ์ •์ƒ ์ƒํ™ฉ์ผ๋•Œ์˜ ๋ฐ˜ํ™˜๊ฐ’ ํƒ€์ž…๊ณผ ์—๋Ÿฌ ์ƒํ™ฉ์—์„œ์˜ ๋ฐ˜ํ™˜๊ฐ’ ํƒ€์ž…์„ ๊ฐ™์ด ์จ์ค˜์•ผํ•˜์ง€๋งŒ, Result๋ฅผ ์žฌ์ •์˜ํ•˜๊ณ  ๋‚˜๋ฉด ์ •์ƒ ์ƒํ™ฉ์—์„œ์˜ ๋ฐ˜ํ™˜๊ฐ’ ํƒ€์ž…๋งŒ ๊ธฐ๋กํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌ ์ƒํ™ฉ์—์„œ์˜ ๋ฐ˜ํ™˜๊ฐ’ ํƒ€์ž…์€ ์•”๋ฌต์ ์œผ๋กœ ๋‚ด๊ฐ€ ์ •์˜ํ•œ ์—๋Ÿฌ ํƒ€์ž…์ด ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  handle_commandํ•จ์ˆ˜์—์„œ๋Š” ?์—ฐ์‚ฐ์ž(try์—ฐ์‚ฐ์ž)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ณ , map_err ๋“ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

pub fn handle_command(cmd: &str) -> Result<usize> {
    // use ? operator if it doesn't need to check the error value in this function
    let passed = check_command(cmd)?;
    println!("Good command passed: status={}", passed);

    let _ = check_command(cmd)
        .map_err(|e| println!("Command failed: error={:?}", e))
        .map(|s| println!("Command passed: status={}", s));

    if let Ok(status) = check_command(cmd) {
        println!("wierd but ok: status={:?}", status);
    } else {
        println!("Command failed: command={}", cmd);
    }
    Ok(0)
}

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

์•„๋ž˜๋Š” handle_command ํ•จ์ˆ˜๋ฅผ mycommand.rs๋กœ ์˜ฎ๊ธฐ๊ณ  handle_command๋ฅผ ํ˜ธ์ถœํ•˜๋Š” super_handle_command์„ main.rs์— ๋งŒ๋“ค์–ด์ค€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// src/error/mycommand.rs
#[derive(Debug, PartialEq)]
pub enum MyError {
    UnsupportedCommand,
    WrongInput(String),
    UnknownValue {
        name: String,
        expected: String,
        found: String,
    },
    // Add more error cases
}

pub type Result<T, E = MyError> = std::result::Result<T, E>;

// fn check_command(cmd: &str) -> Result<usize, String> {
fn check_command(cmd: &str) -> Result<usize> {
    match cmd {
        "good" => Ok(0),
        "unsupported" => Err(MyError::UnsupportedCommand),
        "bad" => Err(MyError::WrongInput(format!(
            "Cannot handle the command:{}",
            cmd
        ))),
        _ => Err(MyError::UnknownValue {
            name: "Wierd Command Error".to_owned(),
            expected: "good".to_owned(),
            found: cmd.to_owned(),
        }),
    }
}

pub fn handle_command(cmd: &str) -> Result<usize> {
    // use ? operator if it doesn't need to check the error value in this function
    let passed = check_command(cmd)?;
    println!("Good command passed: status={}", passed);

    let _ = check_command(cmd)
        .map_err(|e| println!("Command failed: error={:?}", e))
        .map(|s| println!("Command passed: status={}", s));

    if let Ok(status) = check_command(cmd) {
        println!("wierd but ok: status={:?}", status);
    } else {
        println!("Command failed: command={}", cmd);
    }
    Ok(0)
}
// src/error/main.rs
mod mycommand;
use crate::mycommand::*;

#[derive(Debug, PartialEq)]
pub enum SuperError {
    CommandError(MyError),
}

pub type Result<T, E = SuperError> = std::result::Result<T, E>;

impl From<MyError> for SuperError {
    fn from(err: MyError) -> Self {
        Self::CommandError(err)
    }
}

fn super_handle_command(cmd: &str) -> Result<usize> {
    Ok(mycommand::handle_command(cmd)?)
}

fn main() {
    let status: Result<usize, SuperError> = super_handle_command("bad");
    if status.is_ok() {
        println!("Everything is fine");
    } else {
        println!("I don't feel good:{:?}", status);
    }
}
$ cargo run --bin error
   Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/error`
I don't feel good:Err(CommandError(WrongInput("Cannot handle the command:bad")))

main ๋ชจ๋“ˆ์€ mycommand.rs ๋ชจ๋“ˆ์˜ ์—๋Ÿฌ ํƒ€์ž…์„ ํฌํ•จํ•˜๋Š” ์ƒˆ๋กœ์šด ์—๋Ÿฌ ํƒ€์ž… SuperError๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  SuperError ํƒ€์ž…์„ ์œ„ํ•œ From ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. handle_command์—์„œ ๋ฐ˜ํ™˜๋œ MyErrorํƒ€์ž…์ด ์ž๋™์œผ๋กœ SuperError๋กœ ๋ณ€ํ™˜๋˜์„œ mainํ•จ์ˆ˜๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ MyError์ด์™ธ์— ๋˜๋‹ค๋ฅธ ํ•˜์œ„ ์—๋Ÿฌ ํƒ€์ž…์ด ์ƒ๊ธฐ๋ฉด From<์ƒˆ๋กœ์šด ํ•˜์œ„ ๋ชจ๋“ˆ์˜ ์—๋Ÿฌ ํƒ€์ž…> ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

mainํ•จ์ˆ˜์—์„œ ์—๋Ÿฌ ๊ฐ’์ด ์ถœ๋ ฅ๋œ ๊ฒƒ์„ ๋ณด๋ฉด ์ƒ์œ„ ์—๋Ÿฌ ํƒ€์ž… SuperError์•ˆ์— ํ•˜์œ„ ์—๋Ÿฌ ํƒ€์ž… MyError๊ฐ€ ์ €์žฅ๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

super_handle_commandํ•จ์ˆ˜๋Š” ๋‹จ ํ•œ์ค„์ด์ง€๋งŒ ์‚ฌ์‹ค์€ ์•ˆ๋ณด์ด๋Š” ๋ช‡๊ฐ€์ง€ ๋™์ž‘์ด ์ˆจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

fn super_handle_command(cmd: &str) -> Result<usize> {
    Ok(mycommand::handle_command(cmd)?)
}

mycommand::handle_command๊ฐ€ ์„ฑ๊ณตํ–ˆ์„ ๊ฒฝ์šฐ

  1. ?์—ฐ์‚ฐ์ž๋Š” usize๊ฐ’์„ ๊บผ๋‚ด์คŒ.
  2. super_handle_command๋Š” Ok(์„ฑ๊ณตํ•œ ๊ฒฐ๊ณผ๊ฐ’)์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ๋จ

mycommand::handle_command๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ

  1. ?์—ฐ์‚ฐ์ž๋Š” MyErrorํƒ€์ž…์˜ ์—๋Ÿฌ๋ฅผ super_handle_command์˜ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ๋„˜๊ธฐ๋ ค๊ณ  ์‹œ๋„ํ•จ
  2. SuperError์˜ From ํŠธ๋ ˆ์ดํŠธ์— ์˜ํ•ด MyError๊ฐ€ SuperError::CommandError๋กœ ๋ณ€ํ™˜๋จ
  3. super_handle_command์˜ ์ตœ์ข…์ ์ธ ๋ฐ˜ํ™˜๊ฐ’์€ SuperError::CommandError๊ฐ€ ๋จ

๊ฐ์ฒด์˜ ์ˆ˜๋ช…์„ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” Life-time ๋ผ์ดํ”„ํƒ€์ž„

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

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

// src/lifetime/main.rs
use std::collections::HashMap;

struct Item {
    name: String,
    price: f32,
    quantity: u32,
}

struct Storage {
    items: HashMap<String, Item>,
}

impl Storage {
    fn new() -> Self {
        Storage {
            items: HashMap::new(),
        }
    }

    fn storage_store(&mut self, item: Item) {
        self.items.insert(item.name.clone(), item);
    }
}

struct Statistics<'a> {
    items: &'a HashMap<String, Item>,
}

impl<'a> Statistics<'a> {
    fn new(items: &'a HashMap<String, Item>) -> Self {
        Statistics { items }
    }

    fn get_average(&self) -> f32 {
        let total = self.items.values().fold(0.0, |acc, i| acc + i.price);
        let count = self.items.values().fold(0, |acc, i| acc + i.quantity);
        total / count as f32
    }
}

fn main() {
    let mut mystorage = Storage::new();

    let apple = Item {
        name: "apple".to_string(),
        price: 1.0,
        quantity: 10,
    };
    mystorage.storage_store(apple);

    let banana = Item {
        name: "banana".to_string(),
        price: 2.0,
        quantity: 20,
    };
    mystorage.storage_store(banana);

    let stats = Statistics::new(&mystorage.items);
    println!("{}", stats.get_average());
}

Storage๋Š” ์ฐฝ๊ณ ์— ์ €์žฅ๋œ ๊ณผ์ผ์˜ ๊ฐฏ์ˆ˜์™€ ๊ฐ€๊ฒฉ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ณผ์ผ ์ด๋ฆ„์„ ํ‚ค๋กœ ๊ฐ–๊ณ , ๊ณผ์ผ์— ๋Œ€ํ•œ ์ •๋ณด Item๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ’์œผ๋กœ ๊ฐ–๋Š” ํ•ด์‰ฌ๋งต์ž…๋‹ˆ๋‹ค.

{
    "apple": Item {name: "apple", price: 1.0, quantity: 1.0},
    "banana": Item {name: "banana", price: 2.0, quantity: 20}
}

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

    fn get_average(&self) -> f32 {
        let total = self.items.values().fold(0.0, |acc, i| acc + i.price);
        let count = self.items.values().fold(0, |acc, i| acc + i.quantity);
        total / count as f32
    }

๋‹จ๊ณ„๋ณ„๋กœ ์„ค๋ช…์„ ํ•ด๋ณด๋ฉด

  1. items๋Š” Storage๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” items์˜ ๋ ˆํผ๋Ÿฐ์Šค์ž…๋‹ˆ๋‹ค
  2. items.values()๋Š” ํ•ด์‰ฌ๋งต์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ’์— ๋Œ€ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค
  3. ์ดํ„ฐ๋ ˆ์ดํ„ฐ์˜ fold๋ฉ”์†Œ๋“œ๋Š” ์ดˆ๊ธฐ๊ฐ’ 0์„ ๊ฐ–๊ณ , items๋ผ๋Š” ํ•ด์‰ฌ๋งต์˜ ๊ฐ ๊ฐ’๋“ค์—์„œ price ๊ฐ’๋“ค์„ ์ฝ์–ด์„œ acc ๋ณ€์ˆ˜์— ๋ˆ„์ ํ•ด์„œ ๋”ํ•ฉ๋‹ˆ๋‹ค. acc๋Š” ์ตœ์ข…์—๋Š” ๋ชจ๋“  ๊ณผ์ผ๋“ค์˜ ๊ฐ€๊ฒฉ์„ ๋‹ค ํ•ฉ์นœ ๊ฐ’์ด ๋˜๊ณ  total์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  4. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ count์—๋Š” ๋ชจ๋“  ๊ณผ์ผ๋“ค์˜ ๊ฐฏ์ˆ˜๋ฅผ ๋‹ค ํ•ฉ์นœ ๊ฐ’์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  5. get_average๋Š” total์„ count๋กœ ๋‚˜๋ˆˆ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์‹ค ๊ณ„์‚ฐ์‹์˜ ์˜๋ฏธ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ Storage๋ผ๋Š” ๊ฐ์ฒด์˜ ํ•„๋“œ๋ฅผ Statistics๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฒŒ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Statistics๊ฐ€ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๋Š” Storage ๊ฐ์ฒด๊ฐ€ Statistic๋ณด๋‹ค ๋จผ์ € ํ•ด์ง€๋˜๋ฉด ์•ˆ๋œ๋‹ค๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

struct Statistics<'a> {
    items: &'a HashMap<String, Item>,
}

impl<'a> Statistics<'a> {
    fn new(items: &'a HashMap<String, Item>) -> Self {
        Statistics { items }
    }

Statistics ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•  ๋•Œ, &Hashmap๊ณผ ๊ฐ™์ด ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ &'a HashMap์œผ๋กœ ๋Ÿฌํผ๋Ÿฐ์Šค ๊ธฐํ˜ธ์— 'a๋ผ๋Š” ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ items๋ผ๋Š” ๋ ˆํผ๋Ÿฐ์Šค์˜ ์ˆ˜๋ช…์ด a๋กœ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  newํ•จ์ˆ˜์—์„œ ์ „๋‹ฌ๋ฐ›์€ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋ฐ”๋กœ ์ˆ˜๋ช…์ด๋ฆ„ a๋กœ ์ €์žฅํ•˜๋Š” ๋ ˆํผ๋Ÿฐ์Šค์ž…๋‹ˆ๋‹ค.

Statistics ์ž๊ธฐ ์ž์‹ ๋ณด๋‹ค Statistics๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋” ๊ธด ์ˆ˜๋ช…(๋” ๋‚˜์ค‘์— ๊ฐ์ฒด๊ฐ€ ํ•ด์ง€๋˜์–ด์•ผํ•จ)์„ ๊ฐ€์ง€๊ณ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋Ÿฌ์ŠคํŠธ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” Statistics๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๋ ˆํผ๋Ÿฐ์Šค์˜ ์ˆ˜๋ช… ์ด๋ฆ„๋“ค์„ ๊ฐ€์ง€๊ณ , Statistics๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ๊ฐ์ฒด๋“ค ์ค‘ ์–ด๋Š ํ•œ์ชฝ์ด Statistics ๊ฐ์ฒด๋ณด๋‹ค ๋จผ์ € ํ•ด์ง€๋˜์ง€ ์•Š๋„๋ก ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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