์—ด๊ฑฐํ˜•

enum ํ‚ค์›Œ๋“œ๋Š” ๋ช‡๊ฐ€์ง€ ๋ณ€ํ˜•(variant)์œผ๋กœ ํ‘œํ˜„๋˜๋Š” ์—ด๊ฑฐํ˜• ํƒ€์ž…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:

#[derive(Debug)]
enum Direction {
    Left,
    Right,
}

#[derive(Debug)]
enum PlayerMove {
    Pass,                        // ๋‹จ์ˆœ ๋ณ€ํ˜•
    Run(Direction),              // ํŠœํ”Œ ๋ณ€ํ˜•
    Teleport { x: u32, y: u32 }, // ๊ตฌ์กฐ์ฒด ๋ณ€ํ˜•
}

fn main() {
    let m: PlayerMove = PlayerMove::Run(Direction::Left);
    println!("์ด๋ฒˆ ์ฐจ๋ก€: {:?}", m);
}
This slide should take about 5 minutes.

ํ‚ค ํฌ์ธํŠธ:

  • Enumerations allow you to collect a set of values under one type.
  • Direction์€ ๋ณ€ํ˜•์„ ๊ฐ€์ง€๋Š” ์—ด๊ฑฐํ˜• ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” Direction::Left์™€ Direction::Right์˜ ๋‘ ๊ฐ’์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  • PlayerMove is a type with three variants. In addition to the payloads, Rust will store a discriminant so that it knows at runtime which variant is in a PlayerMove value.
  • This might be a good time to compare structs and enums:
    • In both, you can have a simple version without fields (unit struct) or one with different types of fields (variant payloads).
    • You could even implement the different variants of an enum with separate structs but then they wouldnโ€™t be the same type as they would if they were all defined in an enum.
  • Rust๋Š” ํŒ๋ณ„์‹์„ ์ €์žฅํ•˜๋Š” ๋ฐ ์ตœ์†Œํ•œ์˜ ๊ณต๊ฐ„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ•„์š”ํ•œ ๊ฐ€์žฅ ์ž‘์€ ํฌ๊ธฐ์˜ ์ •์ˆ˜๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

    • ํ—ˆ์šฉ๋œ ๋ณ€ํ˜• ๊ฐ’์ด ๋ชจ๋“  ๋น„ํŠธ ํŒจํ„ด์„ ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ž˜๋ชป๋œ ๋น„ํŠธ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒ๋ณ„์‹์„ ์ธ์ฝ”๋”ฉํ•ฉ๋‹ˆ๋‹ค(โ€˜ํ‹ˆ์ƒˆ ์ตœ์ ํ™”โ€™). ์˜ˆ๋ฅผ ๋“ค์–ด Option<&u8>์€ ์ •์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋‚˜ None ๋ณ€ํ˜•์˜ ๊ฒฝ์šฐ NULL์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

    • C์™€์˜ ์—ฐ๋™์„ ์œ„ํ•ด ์‹๋ณ„์ž ๊ฐ’์„ ์ง์ ‘ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

      #[repr(u32)]
      enum Bar {
          A, // 0
          B = 10000,
          C, // 10001
      }
      
      fn main() {
          println!("A: {}", Bar::A as u32);
          println!("B: {}", Bar::B as u32);
          println!("C: {}", Bar::C as u32);
      }

      repr ์†์„ฑ์ด ์—†๋‹ค๋ฉด 10001์ด 2 ๋ฐ”์ดํŠธ๋กœ ํ‘œํ˜„๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹๋ณ„์ž์˜ ํƒ€์ž… ํฌ๊ธฐ๋Š” 2 ๋ฐ”์ดํŠธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๋” ์‚ดํŽด๋ณด๊ธฐ

Rust์—๋Š” enum์ด ๋” ์ ์€ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๋„๋ก ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ์ตœ์ ํ™”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋„ํฌ์ธํ„ฐ ์ตœ์ ํ™”: ์–ด๋–ค ํƒ€์ž…๋“ค์— ๋Œ€ํ•ด์„œ ๋Ÿฌ์ŠคํŠธ๋Š” size_of::<T>()๊ฐ€ size_of::<Option<T>>()์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

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

    use std::mem::transmute;
    
    macro_rules! dbg_bits {
        ($e:expr, $bit_type:ty) => {
            println!("- {}: {:#x}", stringify!($e), transmute::<_, $bit_type>($e));
        };
    }
    
    fn main() {
        unsafe {
            println!("bool:");
            dbg_bits!(false, u8);
            dbg_bits!(true, u8);
    
            println!("Option<bool>:");
            dbg_bits!(None::<bool>, u8);
            dbg_bits!(Some(false), u8);
            dbg_bits!(Some(true), u8);
    
            println!("Option<Option<bool>>:");
            dbg_bits!(Some(Some(false)), u8);
            dbg_bits!(Some(Some(true)), u8);
            dbg_bits!(Some(None::<bool>), u8);
            dbg_bits!(None::<Option<bool>>, u8);
    
            println!("Option<&i32>:");
            dbg_bits!(None::<&i32>, usize);
            dbg_bits!(Some(&0i32), usize);
        }
    }