---
# System prepended metadata

title: 13차 러스트 스터디

---

# 13차 러스트 스터디

## 담당
- 발표: 유병조 님
- 리뷰: 허신 님
- 서기: 정연집 님

## 과제 리뷰
### [디자인패턴 만들어보기](https://github.com/JannLee/rust-study)


## 18. 값의 구조와 매칭되는 패턴
- 패턴은 단순하거나 복잡한 타입의 구조에 값들을 비교하기 위한 러스트의 특별한 문법
- 패턴의 조합
    - 리터럴 값(Literals)
    - 분해한 배열(Array), 열거형(Enum), 구조체(Struct), 튜플(Tuple)
    - 변수(Variable)
    - 와일드카드(Wildcard)
    - 임시 값(Placeholders)
### 18.1. 패턴이 사용될 수 있는 모든 곳
#### match 갈래
- match표현은 match 키워드, 대응 시킬 값, 갈래들로 이루어지고, 각 갈래는 갈래를 나타내는 패턴, 해당 패턴에 값이 대응 될때 실행할 표현으로 구성됩니다.
``` rust
match 값 {
    패턴 => 표현,
    패턴 => 표현,
    패턴 => 표현,
}
```
- match 표현을 사용하기 위해 지켜야할 사항
    - match 표현에 대응 시킬 값이 가질 수 있는 모든 경우의 수를 빠짐 없이 표현해야 함.
- '_' 키워드
    - 명시 하지 않은 값들을 무시할 때 유용

#### if let 조건 표현
- 'if let', 'else if', 'else if let' 표현을 섞어서 사용 가능
- if let표현의 단점
    - match표현과 다르게 컴파일러가 해당 구문이 모든 경우를 다뤘는지 판단하지 않는다는 점
- match와 차이점
    - 'if let'의 경우, 모든 경우수를 매칭시키지 않아도 된다.
``` rust
fn main() {
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age: Result<u8, _> = "34".parse();

    if let Some(color) = favorite_color {
        println!("Using your favorite color, {}, as the background", color);
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
}

```

#### while let 조건 루프
- 조건에 만족하면 계속 반복하게 하는 구문
``` rust
#![allow(unused)]
fn main() {
let mut stack = Vec::new();

stack.push(1);
stack.push(2);
stack.push(3);

while let Some(top) = stack.pop() {
    println!("{}", top);
}

```

#### for 루프
- 패턴 예시
    - for x in y에서 x가 패턴
``` rust
#![allow(unused)]
fn main() {
let v = vec!['a', 'b', 'c'];

for (index, value) in v.iter().enumerate() {
    println!("{} is at index {}", value, index);
} // 튜플을 분해할 수 있음
```
- enumerate 메소드
    - 해당 반복자를 자신의 값과 값의 index를 포함한 튜플들을 순회
#### let 구문
- let PATTERN = EXPRESSION;
- 변수명 자체가 하나의 패턴이 된다. 
```rust
let PATTERN = EXPRESSION;
```
- 튜플 매칭시 갯수가 서로 맞아야 한다.
- _를 사용해 값을 무시할 수 있음

#### 함수의 매개변수
- 함수 매개변수는 패턴
``` rust
fn foo(x: i32) { // x가 패턴
    // code goes here
}


```
- 클로저도 동일하게 사용이 가능하다

### 18.2. 반증 가능성: 패턴의 매칭이 실패할 수도 있는 경우

- 반증 가능 패턴
    - 주어진 값에 대응이 실패할 수 있는 패턴.
    - ex) if let Some(x) = a_value; // a_value가 None일때 대응하지 못해 실패

- 반증 불가 패턴
    - 주어진 어떠한 값에도 대응되는 패턴 (절대 실패할 수 없는 패턴)
    - ex) let x = 5; 
- 'let', 'for'구문
    - 반증불가한 패턴만 허용
- 'if let', 'while let'
    - 반증 가능 패턴만 허용
- let 에서 반증 불가 패턴 사용시,
``` rust
let Some(x) = some_option_value; // => if let을 사용
```

### 18.3. 패턴 문법의 모든 것

#### 18.3.1 리터럴 매칭
- 패턴과 리터럴을 직접 매칭하는 코드
``` rust
#![allow(unused)]
fn main() {
let x = 1;

match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    _ => println!("anything"),
}
}

```

#### 18.3.2 명명 변수 매칭

- 갈래에서 y 변수를 새로 만들어 기존의 것이 가려지도록 한 match 표현
```rust
fn main() {
    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),    // 정의된 변수 x 와 매칭되지 않으니, 해당 코드는 실행되지 않고 넘어갑니다.
        Some(y) => println!("Matched, y = {:?}", y), // 기존의 y가 아닌 새 변수 y이며 x의 값인 5가 대입됨
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}, y = {:?}", x, y); // 여기서 y는 기존 변수 y이므로 y = 10
}

// 출력
// Matched, y = 5
// at the end: x = Some(5), y = 10
```

#### 18.3.3 다중 패턴
- 여러 패턴 패칭
    - '|'키워드: or를 의미
```rust=
#![allow(unused)]
fn main() {
let x = 1;

match x {
    1 | 2 => println!("one or two"),
    3 => println!("three"),
    _ => println!("anything"),
}
}

```

#### 18.3.4 `...`를 이용한 값의 범위 매칭

- `1 | 2 | 3 | 4 | 5` 대신 `1 ... 5`로 간편하게 표현 가능
- 숫자 값이나 char 값에만 사용할 수 있습니다.
```rust
let x = 5;

match x {
    1 ... 5 => println!("one through five"),
    _ => println!("something else"),
}
```
- char 값 매칭 예제
``` rust
#![allow(unused)]
fn main() {
let x = 'c';

match x {
    'a' ... 'j' => println!("early ASCII letter"),
    'k' ... 'z' => println!("late ASCII letter"),
    _ => println!("something else"),
}
}
```
#### 18.3.5 값을 해체하여 분리하기
- 패턴을 이용해 구조체, 열거형, 튜플, 참조자 등의 값들을 해체(destructuring)

##### 구조체 해체하기
```rust
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 7 };    //p 변수의 필드인 x 와 y 에 각각 대응되는 a 와 b 변수를 생성

    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);
}

```
- 패턴내 변수의 이름이 꼭 구조체 내 필드명과 일치할 필요 없음. 하지만 기억하기 쉽도록 필드명을 일치시키는 것이 일반적이다.

##### 열거형 해체
- 열거형을 해체하기위한 패턴은 해당 열거형에 내장된 데이터의 정의 방식이 일치해야한다.
- 다른 종류의 값들을 갖는 열거형 variant 해체
```rust
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn main() {
    let msg = Message::ChangeColor(0, 160, 255);

    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.")
        },
        Message::Move { x, y } => {
            println!(
                "Move in the x direction {} and in the y direction {}",
                x,
                y
            );
        }
        Message::Write(text) => println!("Text message: {}", text),
        Message::ChangeColor(r, g, b) => {
            println!(
                "Change the color to red {}, green {}, and blue {}",
                r,
                g,
                b
            )
        }
    }
}

// 출력
// Change the color to red 0, green 160, and blue 255
```

##### 참조자 해체
- 패턴내에서 '&'키워드를 이용해 참조자를 해체해야함.
```rust
#![allow(unused)]
fn main() {
struct Point {
    x: i32,
    y: i32,
}

let points = vec![
    Point { x: 0, y: 0 },
    Point { x: 1, y: 5 },
    Point { x: 10, y: -3 },
];

let sum_of_squares: i32 = points
    .iter()
    .map(|&Point { x, y }| x * x + y * y)
    .sum();
}

```
-  &Point { x, y } 에서 & 를 뺀다면 타입 불일치(type mismatch) 오류가 발생
```result
error[E0308]: mismatched types
  -->
   |
14 |         .map(|Point { x, y }| x * x + y * y)
   |               ^^^^^^^^^^^^ expected &Point, found struct `Point`
   |
   = note: expected type `&Point`
              found type `Point`

```

-  
##### 구조체와 튜플 해체
``` rust
let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 });
```

#### 18.3.6 패턴 내에서 값 무시하기
- 패턴 내 값을 _, ..을 사용해 무시할 수 있다.

##### _ 를 이용해 전체 값 무시하기
- '_'언더스코어 와일드카드 패턴
    - 어떤 값과도 매치되지만 값으로 바인드(bind) 하지는 않는 것으로 사용
- 함수 시그니처에서 _ 사용하기
- 사용하지 않는 매개 변수에 _를 사용하면 컴파일러가 경고를 하지 않음 
- 언더 스코어가 아닌 이름을 사용할 경우 경고.
```rust
fn foo(_: i32, y: i32)
    println!("This code only uses the y parameter: {}", y);
}

fn main() {
    foo(3, 4); // 첫번째 인자로 전달된 값인 3 을 완벽히 무시
}

// 출력
// This code only uses the y parameter: 4
```

##### 중첩된 _ 를 이용해 값의 일부 무시하기
- _ 를 다른 패턴 내에 사용해서 값의 일부를 무시할 수도 있습니다
- 값의 일부를 테스트 하려는데 해당 코드에서 그 외의 나머지 부분은 필요하지 않을때 이 기능을 사용할 수 있습니다.
```rust
#![allow(unused)]
fn main() {
let mut setting_value = Some(5);
let new_setting_value = Some(10);

match (setting_value, new_setting_value) {
    (Some(_), Some(_)) => {
        println!("Can't overwrite an existing customized value");
    }
    _ => {
        setting_value = new_setting_value;
    }
}

println!("setting is {:?}", setting_value);
}
// 실행 결과 
// Can't overwrite an existing customized value 와 setting is Some(5) 를 출력
```

##### 언더스코어로 시작하는 이름을 이용해 쓰이지 않는 변수 무시하기
- 프로토타입을 만드는 중이거나 프로젝트를 막 시작했을 때와 같이 아직 사용하진 않아도 미리 변수를 만들어 두는 것이 유용할 때도 있습니다.
- _는 값을 바인드하지 않고 
- _변수명은 값을 바인드한다. 

```rust
fn main() {
    let _x = 5;
    let y = 10;
}

```
##### .. 를 이용해 값의 나머지 부분 무시하기
- 값의 일부만 사용하고 나머지는 무시하기 위해 '..' 구문을 사용
- .. 패턴은 우리가 패턴에서 명시하지 않은 값의 나머지 부분을 모두 무시
```rust
#![allow(unused)]
fn main() {
struct Point {
    x: i32,
    y: i32,
    z: i32,
}

let origin = Point { x: 0, y: 0, z: 0 };

match origin {
    Point { x, .. } => println!("x is {}", x),
}
}

```
- ..을 사용할 땐 모호하지 않아야 한다. 
``` rust
fn main() {//모호한 예시
    let numbers = (2, 4, 8, 16, 32);

    match numbers {
        (.., second, ..) => {
            println!("Some numbers: {}", second)
        },
    }
}
```


#### 18.3.7 ref 와 ref mut 를 이용해 패턴 내에서 참조자 생성하기
- 가변 참조자 사용
    - 매치된 패턴 내에서 값을 변경하기 위해 가변 참조자를 생성하려면 &mut 대신 ref mut 을 사용해야 합니다
    - & 는 새 참조자를 생성하는 것이 아닌 이미 존재하는 가변 참조자를 매치시키는데 사용

#### 18.3.8 매치 가드를 이용한 추가 조건
- 매치 가드(match guard) 
    - match 갈래 뒤에 추가로 붙는 if 조건으로, 이것이 있을 경우 패턴 매칭과 해당 조건이 모두 만족되어야 해당 갈래가 선택됨.
```rust
#![allow(unused)]
fn main() {
let num = Some(4);

match num {
    Some(x) if x < 5 => println!("less than five: {}", x),
    Some(x) => println!("{}", x),
    None => (),
}
}

```
- match 표현의 패턴 내에서 새로 생성한 변수가 기존에 있던 match 바깥의 변수를 가려버려서 기존의 변수를 테스트 할 수 없다. 이문제를 해결하기 위한 예시는 아래와 같다.
```rust
fn main() {
    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        Some(n) if n == y => println!("Matched, n = {:?}", n),
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}, y = {:?}", x, y);
}

```

```rust
#![allow(unused)]
fn main() {
let x = 4;
let y = false;

match x {
    4 | 5 | 6 if y => println!("yes"),
    _ => println!("no"),
}
}

```
- 첫 번째 갈래의 패턴에 매치
- 두 번째 갈래로 이동하고 매치되며, 프로그램은 no 를 출력

#### 18.3.9 @ 바인딩
- at 연산자인 @ 
    - 해당 값이 패턴과 매치되는지 확인하는 동시에 해당 값을 갖는 변수를 생성할 수 있도록 해줍니다.
```rust
#![allow(unused)]
fn main() {
enum Message {
    Hello { id: i32 },
}

let msg = Message::Hello { id: 5 };

match msg {
    Message::Hello { id: id_variable @ 3...7 } => {
        println!("Found an id in range: {}", id_variable)
    },
    Message::Hello { id: 10...12 } => {
        println!("Found an id in another range")
    },
    Message::Hello { id } => {
        println!("Found some other id: {}", id)
    },
}
}
```
- 3...7 범위 앞에 id_variable @ 를 지정하는 것으로 값이 범위 패턴과 매치되는지 테스트하면서 해당 값을 캡쳐할(capturing) 수 있습니다.

#### 정리

- 러스트의 패턴은 다른 종류의 데이터를 구별하는데 굉장히 유용
- match 표현 내에서 패턴을 사용하면 러스트가 여러분의 패턴이 모든 가능한 값을 커버할 수 있다는 것을 보장

## 차주 일정
- 스터디 장: 19. 고급 기능들
- 날짜: 2022-09-07
- 과제: 18장에서 배운 것들을 활용하여 자신이 지금까지 수행한 과제 중 하나 리팩토링하기

## 벌금현황
- 이지한: 0
- 김기덕: 0
- 유병조: 0
- 이명수: 0
- 이재현: 0
- 정연집: 10,000
- 허신: 10,000

## 회고
- 이지한: 
- 김기덕: [github 다양한 디자인패턴 저장소 목록](https://github.com/search?o=desc&q=rust+design+pattern&s=stars&type=Repositories)을 참고해서 과제했어요! 이번장에서 공부한 내용을 좀 능숙하게 쓸 수 있으면 좋겠습니다!
- 유병조: 패턴을 사용해서 간결하게 코드를 짤 수 있을거 같아서 좋아요~
- 이명수: 싱글톤 구현하다 낙오했어요 ㅜㅜ
- 이재현: 지금까지 warning때 자주 봤던 _나 for문 같은데서 썼던 ..를 패턴이라는 개념으로 정리가 되서 좋았던 것 같습니다 
- 정연집: 많이 쓸 것 같은 매칭에 대해 자세히 배운 것 같아서 좋았습니다.
- 허신: 이전에 if let 구문이 이해가 안됐었는데 오늘 17장 "패턴" 문법 통해서 잘 정리된 것 같아요.