IT’s Portfolio

[Rust] Start Rust (Day 11) - Enums and Pattern Matching [1] λ³Έλ¬Έ

Development Study/Rust

[Rust] Start Rust (Day 11) - Enums and Pattern Matching [1]

f1r3_r41n 2023. 2. 3. 15:26
728x90
λ°˜μ‘ν˜•

πŸ¦€ Rust Day 11

🏳️ Enums and Pattern Matching

  • μ—΄κ±°μž(enumerations, enums) λŠ” μ‚¬μš© κ°€λŠ₯ν•œ κ°’λ§Œ λ‚˜μ—΄ν•œ νƒ€μž…μ„ μ •μ˜ν•  λ•Œ μ‚¬μš©
  • νŒ¨ν„΄ 맀칭은 μ—΄κ±°μžκ°€ 가진 μ—¬λŸ¬ 값에 λŒ€ν•΄ 각기 λ‹€λ₯Έ μ½”λ“œλ₯Ό μ‰½κ²Œ μ‹€ν–‰ν•  수 μžˆλŠ” 방법
  • 러슀트의 μ—΄κ±°μžλŠ” F#, OCaml, ν•˜μŠ€μΌˆ(Haskell) κ³Ό 같은 ν•¨μˆ˜ν˜• μ–Έμ–΄μ˜ λŒ€μˆ˜μ‹(algebraic) 데이터 νƒ€μž…μ— 더 κ°€κΉŒμ›€

1️⃣ μ—΄κ±°μž μ •μ˜ν•˜κΈ°

  • IP μ£Όμ†ŒλŠ” 버전 4λ‚˜ 버전 6 ν˜•μ‹μ˜ μ£Όμ†Œμ§€λ§Œ λ™μ‹œμ— 두 ν˜•μ‹μ„ 지원할 수 μ—†μŒ
  • μ΄λŸ¬ν•œ IP μ£Όμ†Œμ˜ νŠΉμ§• 덕뢄에 κ΅¬μ‘°μ²΄λ³΄λ‹€λŠ” μ—΄κ±°μž 데이터 ꡬ쑰λ₯Ό μ μš©ν•˜λŠ” 것이 적합함
    • μ—΄κ±°μžμ— λ‚˜μ—΄ν•œ 값은 λ°˜λ“œμ‹œ ν•˜λ‚˜λ§Œ μ‚¬μš©ν•  수 있음
enum IpAddrKind {
    V4,
    V6,
}
  • IP μ£Όμ†Œμ˜ ν˜•μ‹μ„ λ‚˜νƒ€λ‚΄λŠ” IPAddrKind μ—΄κ±°μž μ •μ˜ ν›„ 각 ν˜•μ‹μ„ ν‘œν˜„ν•˜κΈ° μœ„ν•œ V4 와 V6 κ°’ μ •μ˜
    • ν•΄λ‹Ή 값듀을 μ—΄κ±°μžμ˜ 열것값(variants) 이라고 칭함
    • IpAddrKind μ—΄κ±°μžλŠ” 이제 μ½”λ“œμ—μ„œ μ‚¬μš©ν•  수 μž‡λŠ” ν•˜λ‚˜μ˜ νƒ€μž…μœΌλ‘œ 간주됨

πŸ€” μ—΄κ±°μžμ˜ κ°’

let ipv4_1 = IpAddrKind::V4;
let ipv6_1 = IpAddrKind::V6;
  • μ—΄κ±°μžμ˜ 각 값을 ν‘œν˜„ν•˜λŠ” μΈμŠ€ν„΄μŠ€
  • μ—΄κ±°μžμ˜ 각 값은 μ‹λ³„μžλ₯Ό μ΄μš©ν•΄ ꡬ뢄함
    • μ‹λ³„μžμ™€ 값은 :: λ¬Έλ²•μœΌλ‘œ ꡬ뢄
fn route(ip_type: IpAddrKind) { }
  • μ—΄κ±°μžλ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ κ°–λŠ” ν•¨μˆ˜λ„ μ •μ˜ν•  수 있음
enum IpAddrKind {
    V4,
    V6,
}

struct IpAddr {
    kind: IpAddrKind,
    address: String,
}

fn main() {
    let home = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };

    let switch = IpAddr {
        kind: IpAddrKind::V6,
        address: String::from("::1"),
    };

    println!("{}\n{}", home.address, switch.address);
}
// Result
// 127.0.0.1
// ::1
  • ꡬ쑰체λ₯Ό μ΄μš©ν•΄ IP μ£Όμ†Œμ˜ μ’…λ₯˜μ™€ 데이터λ₯Ό μ €μž₯함
  • IpAddr ꡬ쑰체 μ •μ˜ ν›„ IpAddrKind μ—΄κ±°μž νƒ€μž…μ˜ kind ν•„λ“œ, String νƒ€μž…μ˜ address ν•„λ“œ μ •μ˜
  • ꡬ쑰체λ₯Ό μ΄μš©ν•΄ IP μ£Όμ†Œμ˜ μ’…λ₯˜μ™€ μ‹€μ œ μ£Όμ†Œλ₯Ό ν•˜λ‚˜λ‘œ λ¬Άμ—ˆκΈ° λ•Œλ¬Έμ— μ—΄κ±°μžμ˜ κ°’κ³Ό κ΄€λ ¨λœ 값을 ν•˜λ‚˜λ‘œ μ²˜λ¦¬ν•  수 있음
#[derive(Debug)]
enum IpAddrKind {
    V4(String),
    V6(String),
}

fn main() {
    let home = IpAddrKind::V4(
        String::from("127.0.0.1")
    );
    let switch = IpAddrKind::V6(
        String::from("::1")
    );

    println!("{:?}\n{:?}", home, switch);
}
// Result
// V4("127.0.0.1")
// V6("::1")
  • 데이터λ₯Ό μ—΄κ±°μžμ˜ 열것값에 직접 μ €μž₯ν•˜μ—¬ ν‘œν˜„ν•¨
  • IpAddr μ—΄κ±°μžλŠ” V4 와 V6 값을 μ •μ˜ν•˜λ©΄μ„œ μ—°κ΄€λœ κ°’μ˜ νƒ€μž…μ„ String νƒ€μž…μœΌλ‘œ λͺ…μ‹œ
  • λ³„λ„μ˜ ꡬ쑰체λ₯Ό μ„ μ–Έν•  ν•„μš”κ°€ μ—†μŒ
#[derive(Debug)]
enum IpAddrKind {
    V4(u8, u8, u8, u8),
    V6(String),
}

fn main() {
    let home = IpAddrKind::V4(
        127, 0, 0, 1
    );
    let switch = IpAddrKind::V6(
        String::from("::1")
    );

    println!("{:?}\n{:?}", home, switch);
}
// Result
// V4(127, 0, 0, 1)
// V6("::1")
  • μ—΄κ±°μžμ— λ‚˜μ—΄λœ 각각의 값을 μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…κ³Ό λ‹€λ₯Έ 수의 μ—°κ΄€ 데이터λ₯Ό λ³΄μœ ν•  수 있음
  • V4 ν˜•μ‹μ˜ μ£Όμ†Œμ— λ„€ 개의 u8 값을 μ €μž₯, V6 ν˜•μ‹μ˜ μ£Όμ†ŒλŠ” κ·ΈλŒ€λ‘œ String νƒ€μž…
  • κ΅¬μ‘°μ²΄λ‘œλŠ” 이런 데이터 ꡬ쑰λ₯Ό κ°–μΆœ 수 μ—†μŒ
  • μ—΄κ±°μžμ˜ κ°’μ—λŠ” λ¬Έμžμ—΄, 숫자, ꡬ쑰체 λ“± μ–΄λ–€ μ’…λ₯˜μ˜ 데이터 도 μ €μž₯ν•  수 있음
    • λ‹€λ₯Έ μ—΄κ±°μžλ₯Ό μ €μž₯해도 무방함
  • ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— μ—΄κ±°μžκ°€ μ •μ˜λ˜μ–΄ μžˆλ‹€κ³  해도 ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— μ •μ˜ν•œ νƒ€μž…μ„ μ½”λ“œμ˜ λ²”μœ„λ‘œ κ°€μ Έμ˜€μ§€ μ•ŠλŠ” ν•œ μ•„λ¬΄λŸ° 문제 없이 같은 μ΄λ¦„μ˜ νƒ€μž…μ„ μž¬μ •μ˜ν•  수 있음
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32)
}
  • κ°œλ³„ 값을 각기 λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ μ •μ˜ν•œ Message μ—΄κ±°μž
    • Quit : μ—°κ΄€ 데이터λ₯Ό 갖지 μ•ŠμŒ
    • Move : 읡λͺ… ꡬ쑰체(anonymous struct) 포함
    • Write : ν•˜λ‚˜μ˜ String κ°’ 포함
    • ChangeColor : μ„Έ 개의 i32 κ°’ 포함
    • 각기 λ‹€λ₯Έ ꡬ쑰체 νƒ€μž…μ„ μ •μ˜ν•˜λŠ” 것과 μœ μ‚¬ν•¨
      • λ‹€λ₯Έμ  1. struct keywordλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠμŒ
      • λ‹€λ₯Έμ  2. μ—΄κ±°μžμ˜ κ°œλ³„ 값듀은 λͺ¨λ‘ μ—΄κ±°μž νƒ€μž…μ— 속함
struct QuitMsg; // μœ λ‹› ꡬ쑰체
struct MoveMsg { 
    x: i32, 
    y: i32,
}
struct WriteMsg(String); // νŠœν”Œ ꡬ쑰체
struct ChangeColorMsg(i32, i32, i32); // νŠœν”Œ ꡬ쑰체
  • Message μ—΄κ±°μžμ™€ 같은 데이터λ₯Ό μ €μž₯ν•˜λ„λ‘ μ •μ˜ν•œ ꡬ쑰체
  • λ‹€λ₯Έ νƒ€μž…μ˜ ꡬ쑰체λ₯Ό μ •μ˜ν•˜κ²Œ 되면 μ—¬λŸ¬ μ’…λ₯˜μ˜ λ©”μ‹œμ§€λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ μ „λ‹¬λ°›λŠ” ν•¨μˆ˜λ₯Ό μ‰½κ²Œ μ •μ˜ν•  수 μ—†μŒ
#[derive(Debug)]
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32)
}

impl Message {
    fn call(&self) {
        println!("{:?}", self);
    }
}

fn main() {
    let msg = Message::Write(
        String::from("Hello, world!")
    );

    msg.call();
}
// Result
// Write("Hello, world!")
  • impl 블둝을 μ΄μš©ν•˜μ—¬ μ—΄κ±°μžμ˜ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•¨
  • self keyword둜 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” μ—΄κ±°μžμ˜ 값을 κ°€μ Έμ˜¬ 수 있음

πŸ€” Option μ—΄κ±°μžλ₯Ό Null κ°’ λŒ€μ‹  μ‚¬μš©ν•  λ•Œμ˜ μž₯점

  • Option νƒ€μž…μ€ 맀우 λ‹€μ–‘ν•œ κ³³μ—μ„œ ν™œμš© κ°€λŠ₯
    • μ–΄λ–€ 값이 μ‘΄μž¬ν•˜κ±°λ‚˜ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”, μ•„μ£Ό λ²”μš©μ μΈ μ‹œλ‚˜λ¦¬μ˜€μ— μ ν•©ν•˜λ„λ‘ λ””μžμΈλ˜μ—ˆκΈ° λ•Œλ¬Έ
    • νƒ€μž… μ‹œμŠ€ν…œμ΄ 이런 νƒ€μž…μ„ μ œκ³΅ν•œλ‹€λŠ” 것은 μ½”λ“œκ°€ λͺ¨λ“  경우의 수λ₯Ό μ²˜λ¦¬ν•˜κ³  μžˆλŠ”μ§€λ₯Ό μ»΄νŒŒμΌλŸ¬κ°€ 확인할 수 μžˆλ‹€λŠ” 것을 의미
  • λŸ¬μŠ€νŠΈλŠ” λ‹€λ₯Έ μ–Έμ–΄κ°€ 가지고 μžˆλŠ” 널(null) μ΄λΌλŠ” κ°’μ˜ κ°œλ…μ΄ μ—†μŒ
    • 널값 : μ•„λ¬΄λŸ° 값을 갖지 μ•ŠλŠ” 경우λ₯Ό 의미
    • 널값 을 μ§€μ›ν•˜λŠ” μ–Έμ–΄μ—μ„œ λ³€μˆ˜λŠ” 항상 널 μ΄κ±°λ‚˜ 널이 μ•„λ‹Œ(not-null) 두 가지 μƒνƒœ 쀑 ν•˜λ‚˜μž„
  • 널값 의 λ¬Έμ œμ μ€ 널값 을 널이 μ•„λ‹Œ κ°’ 처럼 μ‚¬μš©ν•˜λ €κ³  ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€λŠ” μ μž„
  • λŸ¬μŠ€νŠΈλŠ” μ–΄λ–€ κ°’μ˜ 쑴재 μ—¬λΆ€λ₯Ό ν‘œν˜„ν•˜λŠ” μ—΄κ±°μžλ₯Ό μ •μ˜ν•˜κ³  있음
  • 😎 Option<T>
    • Option<T> μ—΄κ±°μžλŠ” prelude 에 ν¬ν•¨λ˜μ–΄ μžˆκΈ°μ— 열것값도 ν•¨κ»˜ λͺ…μ‹œμ μœΌλ‘œ λ²”μœ„λ₯Ό κ°€μ Έμ˜¬ ν•„μš”κ°€ μ—†μŒ
    • 러슀트의 <T> 문법은 μ œλ„€λ¦­(generic) νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 의미
      • <T> λ§€κ°œλ³€μˆ˜ 덕뢄에 Option μ—΄κ±°μžμ˜ Some 값은 μ–΄λ–€ νƒ€μž…μ˜ 데이터도 μ €μž₯이 κ°€λŠ₯함
      • Ex1. let num = Some(5); $=>$ 숫자 νƒ€μž…
      • Ex2. let msg = Some("Hello, world!"); $=>$ λ¬Έμžμ—΄ νƒ€μž…
      • Some λŒ€μ‹  None 값을 μ΄μš©ν•˜λ©΄ Option<T> μ—΄κ±°μž νƒ€μž…μ„ λͺ…μ‹œν•΄μ•Ό 함
      • Ex1. let null_num: Option<i32> = None;
    • Option<T> 와 T λŠ” λ‹€λ₯Έ νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— μ»΄νŒŒμΌλŸ¬λŠ” μœ νš¨ν•œ 값이 λͺ…ν™•νžˆ μ‘΄μž¬ν•  λ•ŒλŠ” Option<T> 값을 μ‚¬μš©ν•˜λŠ” 것을 ν—ˆλ½ν•˜μ§€ μ•ŠμŒ
      • i8 νƒ€μž…μ˜ 값을 κ°–κ³  μžˆλ‹€λ©΄ 이 값은 항상 μœ νš¨ν•œ 값이라 κ°€μ •ν•˜κΈ° λ•Œλ¬Έμ— 이 값을 μ‚¬μš©ν•˜κΈ° 전에 널 검사 같은 것을 ν•  ν•„μš”κ°€ μ—†μŒ
      • Option<i8> νƒ€μž…μ„ μ‚¬μš©ν•  λ•Œλ§Œ 이 λ³€μˆ˜μ— 값이 없을 κ°€λŠ₯성이 μžˆκΈ°μ— μ‚¬μš©μ— μ•žμ„œ 값이 μ—†λŠ” 경우λ₯Ό μ²˜λ¦¬ν•˜λ €κ³  함
    • T νƒ€μž…μ— λŒ€ν•œ μž‘μ—… μ‹€ν–‰ 전에 Option<T> νƒ€μž…μ„ T νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•΄μ•Ό 함
  • // ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ Option<T>의 μ •μ˜ enum Option<T> { Some(T), None, }
  • μ–΄λ–€ 값이 널값 을 κ°€μ§ˆ 수 μžˆλ„λ‘ ν•˜λ €λ©΄ Option<T> νƒ€μž… λͺ…μ‹œ
  • 값을 μ‚¬μš©ν•˜κ³ μž ν•˜λ©΄ 이 값이 널인 경우λ₯Ό λ°˜λ“œμ‹œ λͺ…μ‹œμ μœΌλ‘œ 처리
  • Option<T> κ°€ μ•„λ‹Œ λ‹€λ₯Έ νƒ€μž…μ˜ 값을 μ‚¬μš©ν•˜λŠ” 경우라면 이 값은 널이 아닐 κ²ƒμœΌλ‘œ 생각해도 무방
  • Option<T> 의 λ‹€μ–‘ν•œ λ©”μ„œλ“œ in Official Document
  • 톡상 Option<T> 값을 μ‚¬μš©ν•˜λ €λ©΄ μ—΄κ±°μžμ— λ‚˜μ—΄λœ κ°œλ³„ 값을 μ²˜λ¦¬ν•  μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ•Ό 함
    • match ν‘œν˜„μ‹μ„ μ‚¬μš©ν•΄ μ‰½κ²Œ κ΅¬ν˜„ κ°€λŠ₯
      • (1). Some(T) 값을 가진 경우만 μ‹€ν–‰ -> μ—΄κ±°μž μ•ˆμ— μ €μž₯된 T 의 값에 μ ‘κ·Όν•  수 있음
      • (2). None 값을 가진 κ²½μš°μ— μ‹€ν–‰ -> T 값에 μ ‘κ·Ό λΆˆκ°€λŠ₯
728x90
λ°˜μ‘ν˜•
Comments