6 Enum and Pattern Matching

In this chapter, weโ€™ll look at enumerations, also referred to as enums. Enums allow you to define a type by enumerating its possible variants ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์˜ ๋ชฉ๋ก์„ ์—ด๊ฑฐํ•˜์—ฌ ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค๋Š” ์ •์˜๊ฐ€ ๋งˆ์Œ์— ๋“ ๋‹ค. ๋ณดํ†ต ์ƒ๋Œ€์ ์œผ๋กœ ์ƒˆ๋กœ์šด ์–ธ์–ด๋“ค์ด ๋ช…์‹œ์ ์ด๋ฉด์„œ ๊ฒฝ์ œ์ ์ด๋ฉด์„œ ์˜ˆ์œ ๋ฌธ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š”๋ฐ ๋Ÿฌ์ŠคํŠธ์˜ enum์ด ํŠนํžˆ ๊ทธ๋Ÿฐ ๋Š๋‚Œ์ด๋‹ค.

6.1 Defining an Enum

  • ๊ตฌ์กฐ์ฒด๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃนํ™” ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค๋ฉด, enum์€ ํŠน์ •ํ•œ ๊ฐ’์ด ๊ฐ€์งˆ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฐ’์„ ์ •์˜ํ•œ๋‹ค.

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

  • ๊ณต์‹ ๊ฐ€์ด๋“œ์—์„œ๋Š” IP ์ฃผ์†Œ๋ฅผ ๋‹ค๋ฃจ๋Š” ์˜ˆ์ œ๋ฅผ ๋“ค๊ณ  ์žˆ๋‹ค. IP์ฃผ์†Œ๋ผ๋Š” ๊ฐœ๋…์„ ์ฝ”๋“œ๋กœ ‘ํ‘œํ˜„’ํ•œ๋‹ค๋ฉด

    • 4๊ฐœ์˜ 8๋น„ํŠธ ์ˆซ์ž๋กœ ๊ตฌ์„ฑ๋œ IPv4 ์ฃผ์†Œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒฝ์šฐ
    • 8๊ฐœ์˜ 16๋น„ํŠธ ์ˆซ์ž๋กœ ๊ตฌ์„ฑ๋œ IPv6 ์ฃผ์†Œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒฝ์šฐ
  • ์ด๋ ‡๊ฒŒ ๋‘๊ฐ€์ง€ ์ƒํƒœ๋งŒ ์กด์žฌํ•˜๊ณ , ๋ชจ๋“  IP์˜ ๋ฒ„์ „์€ ๋‘๊ฐ€์ง€ ์ค‘ ํ•˜๋‚˜์— ์†ํ•˜๊ฒŒ ๋œ๋‹ค.

  • IP ์ฃผ์†Œ์ด๋ฉด์„œ ์ € ๋‘๊ฐ€์ง€์˜ ์ƒํƒœ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์ƒํƒœ์— ์†ํ•  ์ˆ˜ ์—†๊ณ , ๋‘˜ ๋‹ค์— ์†ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์— enum์„ ์ด์šฉํ•ด์„œ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋ฒ„์ „ 4์™€ ๋ฒ„์ „ 6 ์ฃผ์†Œ ๋ชจ๋‘ ๊ทผ๋ณธ์ ์œผ๋กœ๋Š” IP ์ฃผ์†Œ์ด๋ฏ€๋กœ, ์ฝ”๋“œ๊ฐ€ ์–ด๋–ค ์ข…๋ฅ˜์˜ IP ์ฃผ์†Œ์—๋„ ์ ์šฉ๋˜๋Š” ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋™์ผํ•œ ํƒ€์ž…์œผ๋กœ ์ทจ๊ธ‰๋˜์–ด์•ผ ํ•œ๋‹ค.

  • ์ฆ‰ ๋ชจ๋“ , ๊ณ ์œ ํ•œ, ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์˜ ์—ด๊ฑฐ์ด๋ฏ€๋กœ ์ผ์ • ์ •๋„์˜ ์ถ”์ƒํ™”์˜ ์—ญํ• ์„ ํ•œ๋‹ค.

enum IpAddrKind {
    V4,
    V6,
}

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

fn route(ip_kind: IpAddrKind) {}

route(IpAddrKind::V4);
route(IpAddrKind::V6);
  • ๋ฌธ๋ฒ•์€ enum ํ‚ค์›Œ๋“œ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ๊ฐ ์ƒํƒœ๋Š” ์ค‘๊ด„ํ˜ธ๋กœ ๋ฌถ์ธ ๋ชฉ๋ก์œผ๋กœ ์ •์˜๋œ๋‹ค.

  • ๊ฐ ์ƒํƒœ๋Š” ๊ทธ ์ž์ฒด๋กœ ์œ ํšจํ•œ ๊ฐ’์ด๋‹ค. ์ด ๊ฐ’์€ enum์˜ ์ด๋ฆ„์„ ํ†ตํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

  • enum์˜ ์ด๋ฆ„๊ณผ ์ƒํƒœ์˜ ์ด๋ฆ„์€ ๊ฐ™์€ ์ด๋ฆ„ ๊ณต๊ฐ„์— ์žˆ์œผ๋ฏ€๋กœ, enum์˜ ์ด๋ฆ„์„ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  • enum์— ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

enum IpAddr {
    V4(String),
    V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ ์ƒํƒœ๊ฐ€ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ˆœํžˆ ์—ด๊ฑฐํ˜•์— String์„ ๋งคํ•‘ํ•˜๋Š” ์ •๋„๊ฐ€ ์•„๋‹ˆ๋ผ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒƒ๋“ค๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ ์ƒํƒœ๊ฐ€ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.
struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

enum IpAddr {
    V4(Ipv4Addr),
    V6(Ipv6Addr),
}
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ ์ƒํƒœ๊ฐ€ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
  • ๋‹ค์–‘ํ•œ ๊ฒƒ๋“ค์„ ๋งคํ•‘ํ•˜๋˜, ํ•˜๋‚˜์˜ enumerate variants์— ๊ฐ™์€ ํƒ€์ž…์ด ์•„๋‹Œ ๊ฒƒ๋“ค์„ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
struct QuitMessage; // unit struct
struct MoveMessage {
    x: i32,
    y: i32,
}
struct WriteMessage(String); // tuple struct
struct ChangeColorMessage(i32, i32, i32); // tuple struct
    impl Message {
        fn call(&self) {
            // method body would be defined here
        }
    }

    let m = Message::Write(String::from("hello"));
    m.call();
  • impl๋กœ ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

6.1.1 The Option Enum and Its Advantages Over Null Values

  • Option<T>๋Š” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ •์˜๋œ enum์ด๋‹ค.

  • Option<T>๋Š” Some(T)์™€ None ๋‘๊ฐ€์ง€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค.

  • Option<T>๋Š” null ๊ฐ’์˜ ๋Œ€์•ˆ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Java์˜ Optional๊ณผ ๋น„์Šทํ•œ ๊ฐœ๋…์ด๋‹ค.

  • ๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ(๊ทธ ๋ชจ๋“  variant) ๊ฐ€ ์žˆ๊ณ , ๊ทธ ๋ชจ๋“ ์ผ€์ด์Šค๋ฅผ ๋‹ค๋ค„์•ผํ•˜๋Š”๋ฐ, Option์„ ์‚ฌ์šฉํ•˜๋ฉด ์ •ํ™•ํžˆ ๋ชจ๋“  ์ผ€์ด์Šค๋ฅผ ํ•ธ๋“ค๋ง ํ–ˆ๋Š”์ง€, ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ฒดํฌํ•ด์ค€๋‹ค.

  • ์šฐ๋ฆฌ๋Š” ์–ธ์–ด๋ฅผ ๋ฐฐ์šธ๋•Œ, ํ•ด๋‹น ์–ธ์–ด๊ฐ€ ์–ด๋– ํ•œ ๊ธฐ๋Šฅ์„ ํฌํ•จ(include)ํ•˜๊ณ  ์žˆ๋Š”์ง€์—๋Š” ์ถฉ๋ถ„ํžˆ ์ฃผ๋ชฉํ•˜๋ฉด์„œ, ์–ด๋– ํ•œ ๊ธฐ๋Šฅ์„ ๋ฐฐ์ œ(exclude)ํ•˜๊ณ  ์žˆ๋Š”์ง€์—๋Š” ์ถฉ๋ถ„ํžˆ ์ฃผ๋ชฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

  • ๊ธฐ๋Šฅ์˜ ๋ฐฐ์ œ ๋˜ํ•œ ์–ธ์–ด์˜ ํŠน์ง•์ด๋ผ๋Š” ์ ์„ ์„œ์ ์—์„œ ๊ฐ•์กฐํ•˜๊ณ  ์žˆ๋‹ค.

  • ๊ฒฐ๋ก ์ ์œผ๋กœ Rust๋Š” null์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. null์ด๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์–ธ์–ด์˜ ๋ชจ๋“  ๊ฐ’์€ ๋‘๊ฐ€์ง€ variant๋ฅผ ๊ฐ€์ง„๋‹ค. (null, not null)

Tony Hoare๊ฐ€ null์„ ๋ฐœ๋ช…ํ–ˆ๋Š”๋ฐ, ํ›„์— ์ด๊ฒƒ์ด ‘my billion dollar mistake’๋ผ๊ณ  ๋งํ–ˆ๋‹ค.

๊ณต์‹ ๊ฐ€์ด๋“œ ๋ฌธ์„œ์—์„œ ํ•ด๋‹น ๋‚ด์šฉ๊ณผ ๊ด€๋ จํ•œ ์ธํ„ฐ๋ทฐ ๊ธฐ์‚ฌ๋ฅผ ์ธ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด๊ฒŒ ๋Œ€์ถฉ 60๋…„๋งŒ์˜ ์‚ฌ๊ณผ๋ผ๊ณ  ํ•œ๋‹ค. ํ•ด๋‹น ๊ธฐ์‚ฌ์˜ ๋ฐฐ์ŠคํŠธ ๋Œ“๊ธ€์—๋Š”, “Bjarne Stroustrup์˜ ์‚ฌ๊ณผ๊นŒ์ง€๋Š” 14๋…„์ด ๋” ๋‚จ์•˜๋„ค” ๋ผ๋Š” ๋Œ“๊ธ€์ด ๋‹ฌ๋ ค ์žˆ์–ด ๊ฒ€์ƒ‰ํ•ด๋ดค๋Š”๋ฐ, 1979๋…„์€ cpp์˜ ํƒ„์ƒ๋…„ ์ด์—ˆ๋‹ค.

  • ๋ฌดํŠผ ์‹ค์ œ ๊ตฌํ˜„์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
enum Option<T> {
    None,
    Some(T),
}
  • prelude์—๋Š” Option์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด์„œ(๊ทธ๋งŒํผ ์œ ์šฉํ•˜๊ณ  ์ž์ฃผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ธฐ์—) ๋”ฐ๋กœ includeํ•  ํ•„์š”๊ฐ€ ์—†๊ณ , Option์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” Option::์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

  • Some<T> ๋Š” ์ œ๋„ค๋ฆญ์œผ๋กœ ํŠน์ • ํƒ€์ž…์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.

let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;
  • some_number์˜ ํƒ€์ž…์€ Option<i32>์ด๋‹ค.

  • some_string์˜ ํƒ€์ž…์€ Option<&str>์ด๋‹ค.

  • absent_number์˜ ํƒ€์ž…์€ Option<i32>์ด๋‹ค.

  • ๋ฌดํŠผ ๊ฒฐ๋ก ์ ์œผ๋กœ Some value๋Š” ๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ , None value๋Š” ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • None variant๋Š” ์‚ฌ์‹ค์ƒ null๊ณผ ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ์ง€๋‹ˆ๋Š”๋ฐ, ๊ตณ์ด ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ์ด์œ ๋Š” ๋ญ˜๊นŒ? (์™œ null๋ณด๋‹ค None์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?)

  • ์งง๊ฒŒ ์š”์•ฝํ•˜๋ฉด, Option<T>์™€ T๋Š” ๋‹ค๋ฅธ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— ์ปดํŒŒ์ผ๋Ÿฌ๋Š” Option<T>๋ฅผ ์‚ฌ์šฉ ํ•  ๋•Œ, ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ valid value๋ผ๊ณ  ์ƒ์ •ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

let x: i8 = 5;
let y: Option<i8> = Some(5);

let sum = x + y;
  • ์œ„ ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ ๋˜์ง€ ์•Š๋Š”๋‹ค. Option<i8>์™€ i8์€ ๋‹ค๋ฅธ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ๋‹น์—ฐํ•˜๊ฒŒ๋„ i8๊ณผ i8์ด ์•„๋‹Œ ๋ฌด์—‡์ธ๊ฐ€์˜ ๊ฐ’์„ ๋”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์ง€ ๋ชปํ•œ๋‹ค.

  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ดํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, Option<i8>๋ฅผ ๊ทธ๋ƒฅ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด ์•„๋‹Œ ๋ฌด์—‡์ธ๊ฐ€์˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•œ๋‹ค.

  • ์—ฌ๊ธฐ์„œ ๋ฌด์—‡์ธ๊ฐ€์˜ ์ฒ˜๋ฆฌ๋ž€ ๋ฐ”๋กœ Option์˜ variants๋ฅผ ๋‹ค๋ค„์•ผ ํ•˜๋Š” ๊ฒƒ์ด๊ณ , ๊ทธ๋Ÿฌํ•œ ๊ณผ์ • ์ดํ›„์— null(None) ์— ๋Œ€ํ•œ ๋Œ€์‘์„ ์ง„ํ–‰ํ•˜๊ฒŒ๋œ๋‹ค.

6.2 The match Control Flow Construct

  • match๋Š” ๋‹ค๋ฅธ ์–ธ์–ด์˜ switch์™€ ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

  • Pattern์€ literal value, variable, wild card, tuple, destructured structure, enum ๋“ฑ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.

  • match๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๋กœ ํ•˜์—ฌ๊ธˆ ๋ชจ๋“  ์ผ€์ด์Šค๋ฅผ ๋‹ค๋ฃจ๋Š”์ง€ ํ™•์ธํ•˜๊ฒŒ ํ•œ๋‹ค.

  • ๋™์ „ ์žํŒ๊ธฐ์ฒ˜๋Ÿผ ์ฒ˜์Œ์œผ๋กœ ์ผ์น˜ํ•˜๋Š” ํŒจํ„ด์„ ๋งŒ๋‚˜๋ฉด ํ•ด๋‹น ๋ธ”๋ก์„ ์‹คํ–‰ํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” ๋ฌด์‹œํ•œ๋‹ค.

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
  • if ๋ฌธ๊ณผ ๋‹ค๋ฅธ ์ ์€ ๊ตณ์ด boolean์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ์ ์ด๋‹ค.

  • match์˜ arm์ด๋ž€ =>๊ณผ ,๋กœ ๊ตฌ๋ถ„๋œ ํŒจํ„ด๊ณผ ์‹คํ–‰ ์ฝ”๋“œ ๋ธ”๋ก์ด๋‹ค. ํŒจํ„ด๊ณผ ์ฝ”๋“œ ๋ธ”๋ก์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

  • ๊ฐ๊ฐ์˜ arm์— ์—ฐ๊ด€๋˜์–ด์žˆ๋Š” ์ฝ”๋“œ ๋ธ”๋ก์€ ํ‘œํ˜„์‹์ด๋ฉฐ, ์ด ํ‘œํ˜„์‹์˜ ๊ฒฐ๊ณผ๋Š” match ํ‘œํ˜„์‹์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋œ๋‹ค.

  • ํ•œ ์ค„์„ ๋„˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋Š” {}๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

6.2.1 Patterns That Bind to Values

  • match์˜ ๋˜ ๋‹ค๋ฅธ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์€ ํŒจํ„ด์— ๋งค์นญ๋˜๋Š” ๊ฐ’์„ ๋ฐ”์ธ๋”ฉ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๊ณ , enumd variants ์˜ ๊ฐ’์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.
#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}
  • Quarter variant๋Š” UsState๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:?}!", state);
            25
        },
    }
}
  • Coin::Quarter(state)์—์„œ state๋Š” UsState ํƒ€์ž…์ด ๋œ๋‹ค.\

  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด UsState๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

6.2.2 Matching with Option

  • Option<T>๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋„ match๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ.
fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
  • match rust์˜ ์œ ์—ฐํ•œ enum๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ ๋งค์šฐ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋œ๋‹ค.

  • match ์˜ variable binding ๊ธฐ๋Šฅ ๋•์— ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•˜๊ฒŒ ๋–จ์–ด์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๊ณ , ์‹ค์ œ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ๋„ ์ด์ ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ๋‹ค.

6.3.3 Mathches Are Exhaustive

  • match๋Š” ๋ชจ๋“  ๊ฒฝ์šฐ๋ฅผ ๋‹ค๋ฃจ์ง€ ์•Š์œผ๋ฉด ์ปดํŒŒ์ผ ๋˜์ง€ ์•Š๋Š”๋‹ค.
fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        Some(i) => Some(i + 1),
    }
}
  • ์œ„ ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ ๋˜์ง€ ์•Š๋Š”๋‹ค. None์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ์ด์ฒ˜๋Ÿผ ๋Ÿฌ์ŠคํŠธ์˜ match๋Š” ์ฒ ์ €ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋Š” ์‹ค์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•ด์ค€๋‹ค.

billion dollor mistake๋Š” ์• ์ดˆ์— ๋Ÿฌ์ŠคํŠธ์—์„œ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š๋‹ค๊ณ  ํ•œ ๋ฒˆ ๋” ๋น„๊ผฐ๋‹ค ใ…‹ใ…‹

6.3.4 Catch-all Patterns and The _ Placeholder

  • enum๊ณผ match๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ํŠน์ • ๊ฐ’์— ๋Œ€ํ•ด์„œ๋งŒ ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ , ๋‚˜๋จธ์ง€์— ๋Œ€ํ•ด์„œ๋Š” ์•„์˜ˆ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์„ ๋•Œ๊ฐ€ ์žˆ๋‹ค.
    let dice_roll = 9;
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        other => move_player(other),
    }

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}
    fn move_player(num_spaces: u8) {}
  • ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ 3,7์ด ์•„๋‹Œ ๋ชจ๋“  ๊ฒฝ์šฐ๋Š” other์— ๋งค์นญ๋˜์–ด ์ฒ˜๋ฆฌ๋œ๋‹ค.

  • ์ฐธ๊ณ ๋กœ ๋‹ค๋ฅธ ์–ธ์–ด์˜ switch์—์„œ์™€ ๊ฐ™์ด other์„ ์œ„์— ์“ฐ๋ฉด ๊ทธ ์•„๋ž˜ arm๋“ค์€ ๋น„๊ต์กฐ์ฐจ ์•ˆํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • ๋น„์Šทํ•˜๊ฒŒ catch-all ํ•˜๋ฉด์„œ๋„, ํ•ด๋‹น ๊ฐ’์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์„ ๋•Œ๋Š” _๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

    let dice_roll = 9;
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        _ => (), // or another actions for now do nothing
    }

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}

6.4 Concise Control Flow with if let

  • if let์„ ์‚ฌ์šฉํ•˜๋ฉด, ํ•˜๋‚˜์˜ ๊ฐ’ใ…‚์— ๋Œ€ํ•ด์„œ๋งŒ ๋งค์นญ์„ ํ•˜๊ณ , ๋‚˜๋จธ์ง€๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ฒฝ์šฐ์— match๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
    let some_u8_value = Some(0u8);
    match some_u8_value {
        Some(3) => println!("three"),
        _ => (),
    }

    if let Some(3) = some_u8_value {
        println!("three");
    }
  • ๋‘ ์ฝ”๋“œ ๋ชจ๋‘ ์ •ํ™•ํžˆ ๊ฐ™์€ ๋™์ž‘์„ ํ•œ๋‹ค.

  • if let์€ ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ๋„, verboseํ•œ ์ฝ”๋“œ๋„, ๊ตณ์ด ํ•„์š”์—†๋Š” ๋“ค์—ฌ์“ฐ๊ธฐ๋„ ์—†์• ์ฃผ์ง€๋งŒ, match์˜ exhaustive checking์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.

  • ๊ฒฐ๋ก ์ ์œผ๋กœ syntax sugar์ด๋‹ค.

  • else๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

    let mut count = 0;
    if let Coin::Quarter(state) = coin {
        println!("State quarter from {:?}!", state);
    } else {
        count += 1;
    }

6.5 Summary

๋‹ค์–‘ํ•œ match ์‚ฌ์šฉ ์˜ˆ์ œ

// 1. ํŠธ๋ž˜ํ”ฝ ๋ผ์ดํŠธ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ
enum TrafficLight {
    Red,
    Yellow,
    Green,
}

fn simulate_traffic_light(light: TrafficLight) {
    match light {
        TrafficLight::Red => println!("Stop"),
        TrafficLight::Yellow => println!("Caution"),
        TrafficLight::Green => println!("Go"),
    }
}

// 2. ํŒŒ์ผ ์ฝ๊ธฐ ํ•จ์ˆ˜
use std::fs;

fn read_file(file_path: &str) -> Result<String, String> {
    match fs::read_to_string(file_path) {
        Ok(contents) => Ok(contents),
        Err(_) => Err(String::from("Failed to read the file.")),
    }
}

// 3. ๋™๋ฌผ์˜ ์†Œ๋ฆฌ ์ถœ๋ ฅ
enum Animal {
    Dog,
    Cat,
    Bird,
}

fn make_sound(animal: Animal) {
    match animal {
        Animal::Dog => println!("Woof!"),
        Animal::Cat => println!("Meow!"),
        Animal::Bird => println!("Tweet!"),
    }
}

// 4. ๋ชจ์–‘์˜ ๋ฉด์  ๊ณ„์‚ฐ
enum Shape {
    Circle(f64),
    Triangle(f64, f64),
    Rectangle(f64, f64),
}

fn calculate_area(shape: Shape) -> f64 {
    match shape {
        Shape::Circle(radius) => std::f64::consts::PI * radius * radius,
        Shape::Triangle(base, height) => 0.5 * base * height,
        Shape::Rectangle(width, height) => width * height,
    }
}

// 5. ์ฃผ์†Œ ์ •๋ณด ์ถœ๋ ฅ
enum Address {
    City(String),
    State(String),
    Country(String),
}

struct Location {
    city: String,
    state: String,
    country: String,
}

fn print_city_address(address: Address) {
    match address {
        Address::City(city) => println!("City: {}", city),
        _ => (),
    }
}

// 6. ๋‘ ์˜ต์…˜ ์ฒ˜๋ฆฌ
enum OptionEnum<T> {
    Some(T),
    None,
}

fn process_option(option1: OptionEnum<i32>, option2: OptionEnum<i32>) {
    match (option1, option2) {
        (OptionEnum::Some(val1), OptionEnum::Some(val2)) => println!("Both options have values: {}, {}", val1, val2),
        _ => println!("At least one option is None."),
    }
}

// 7. ์‚ฌ์น™์—ฐ์‚ฐ ํ•จ์ˆ˜
fn calculate_operation(op: &str, num1: f64, num2: f64) -> Result<f64, String> {
    match op {
        "+" => Ok(num1 + num2),
        "-" => Ok(num1 - num2),
        "*" => Ok(num1 * num2),
        "/" => {
            if num2 == 0.0 {
                Err(String::from("Division by zero is not allowed."))
            } else {
                Ok(num1 / num2)
            }
        },
        _ => Err(String::from("Invalid operation.")),
    }
}

// 8. ๊ณ„์ ˆ ์ถœ๋ ฅ
enum Season {
    Spring,
    Summer,
    Autumn,
    Winter,
}

fn print_season_message(season: Season) {
    match season {
        Season::Spring => println!("It's spring!"),
        Season::Summer => println!("It's summer!"),
        Season::Autumn => println!("It's autumn!"),
        Season::Winter => println!("It's winter!"),
    }
}

// 9. ๋กœ๊ทธ์ธ ํ•จ์ˆ˜
fn login(username: &str, password: &str) -> Result<(), String> {
    if password == "correctpassword" {
        Ok(())
    } else {
        Err(String::from("Incorrect password."))
    }
}

// 10. ์ฃผ๋ฌธ ์ƒํƒœ ์ถœ๋ ฅ
enum OrderStatus {
    Pending,
    Completed,
}

fn print_order_status(status: OrderStatus) {
    match status {
        OrderStatus::Pending => println!("Your order is pending."),
        OrderStatus::Completed => println!("Your order is completed."),
    }
}