이 시리즈는 Rust 공식문서를 통해 공부한 흔적임을 밝힙니다.
우리는 오래 전, 열거형에 대해 공부할 때 패턴 매칭에 대해 다룬 바가 있다.
열거형 외에도 패턴 매칭을 사용할 수 있는 상황은 더 존재한다.
이번 시간에는 이것에 대해 좀 더 자세히 알아보도록 하겠다.
패턴은 어떤 값과 비교되어 그것이 일치하면 그 값을 코드에서 사용하는 용도로 이용된다.
match
우리가 열거형과 패턴 매칭에서 배웠던 것처럼 패턴을 match
와 같이 사용할 수 있다.
match
는 하나 이상의 arm으로 이루어져 있는데
arm은 패턴과 표현식으로 이루어진다는 것을 우리는 학습한 바 있다.
arm은 패턴 => 표현식
의 형태를 띄고 있으며
match
와 중괄호 블록 사이에 오는 어떤 값이 어떤 arm의 패턴과 일치한다면
해당 arm의 표현식이 실행된다.
match
표현식에서 유의해야 할 부분은 모든 경우의 수에 대한 arm이 존재해야 한다는 것이다.
모든 것을 일일이 열거할 수 없을 경우에는
맨 마지막에 모든 값에 일치하는 패턴을 넣어 나머지 경우를 모두 포함시킬 수 있다.
우리는 이것을 자리지정자라고 부른다는 것을 이미 배운 바가 있다.
match
에 대한 예제는 충분히 다루어봤으므로 생략한다.
if let
if let
에 대한 것도 열거형과 패턴 매칭 끝자락에 잠깐 다루었다.
match
표현식을 사용하고자 하는데 arm
이 어떤 패턴과 자리지정자 둘 밖에 없다면
match
표현식보다 if let
표현식을 사용하는 게 더 짧고 가독성이 높다는 것이다.
if let
의 중괄호 블록에는 해당 패턴과 일치하는 경우의 표현식을,
else
의 중괄호 블록에는 그렇지 않은 경우의 표현식을 적어 넣는다.
우리는 단일 if let
else
구문만 이야기했지만
if
표현식처럼 if let
표현식도 if let
else if let
else
와 같이 이어갈 수 있다.
심지어는 if let
이 아니라 if
와도 혼용할 수 있다.
이를 위한 간단한 예시로 몇 가지 조건을 검사하는 예제를 작성해보자.
예제의 단순화를 위해 값은 사용자에게 입력받지 않고 하드코딩 하였다.
peter@hp-laptop:~/rust-practice$ cd chapter18
peter@hp-laptop:~/rust-practice/chapter18$ cargo new if_let_example
Created binary (application) `if_let_example` package
peter@hp-laptop:~/rust-practice/chapter18$ cd if_let_example/
peter@hp-laptop:~/rust-practice/chapter18/if_let_example$ vi src/main.rs
src/main.rs
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"); } }
eter@hp-laptop:~/rust-practice/chapter18/if_let_example$ cargo run
Compiling if_let_example v0.1.0 (/home/peter/rust-practice/chapter18/if_let_example)
Finished dev [unoptimized + debuginfo] target(s) in 0.24s
Running `target/debug/if_let_example`
Using purple as the background color
peter@hp-laptop:~/rust-practice/chapter18/if_let_example$
하지만 if let
표현식은 match
와 달리 컴파일러가
모든 경우의 수에 대한 검사를 해주지 못하므로
안전성을 위해서는 if let
이 복잡해진다면 if let
보다는 match
를 사용하는 게 좋겠다.
while let
while let
은 반복 조건이 패턴 일치인 반복문이다.
주어진 값이 주어진 패턴과 일치하는 경우에만 반복하고 일치하지 않아지면 반복을 종료한다.
간단한 예제를 살펴 보도록 하자.
peter@hp-laptop:~/rust-practice/chapter18/if_let_example$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new while_let_example
Created binary (application) `while_let_example` package
peter@hp-laptop:~/rust-practice/chapter18$ cd while_let_example/
peter@hp-laptop:~/rust-practice/chapter18/while_let_example$ vi src/main.rs
src/main.rs
fn main() { let mut stack = Vec::new(); stack.push(1); stack.push(2); stack.push(3); while let Some(top) = stack.pop() { println!("{}", top); } }
peter@hp-laptop:~/rust-practice/chapter18/while_let_example$ cargo run
Compiling while_let_example v0.1.0 (/home/peter/rust-practice/chapter18/while_let_example)
Finished dev [unoptimized + debuginfo] target(s) in 0.21s
Running `target/debug/while_let_example`
3
2
1
peter@hp-laptop:~/rust-practice/chapter18/while_let_example$
pop
메서드는 벡터가 비어있지 않다면 마지막 원소를 Some
에 넣어 반환하고
비어있다면 None
을 반환한다.
그리고 이것이 None
이 되면 while let
의 조건이 충족되지 않아 반복을 종료한다.
for
우리가 그저 반복문이라고만 알고 있던 for
문에도 패턴을 적용할 수 있다.
for 아이템 in 반복자
형태에서 아이템
에 패턴이 들어간다.
반복자의 아이템이 패턴에 일치해야만 컴파일 오류가 발생하지 않는다.
우리는 평소에 for
문을 다음과 같이 사용했다.
peter@hp-laptop:~/rust-practice/chapter18/while_let_example$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new for_example
Created binary (application) `for_example` package
peter@hp-laptop:~/rust-practice/chapter18$ cd for_example/
peter@hp-laptop:~/rust-practice/chapter18/for_example$ vi src/main.rs
src/main.rs
fn main() { let v = vec!['a', 'b', 'c']; for (index, value) in v.iter().enumerate() { println!("{} is at index {}", value, index); } }
peter@hp-laptop:~/rust-practice/chapter18/for_example$ cargo run
Compiling for_example v0.1.0 (/home/peter/rust-practice/chapter18/for_example)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/for_example`
a is at index 0
b is at index 1
c is at index 2
peter@hp-laptop:~/rust-practice/chapter18/for_example$
튜플 형태의 패턴에 아이템의 튜플이 매치되어 각각을 변수처럼 사용할 수 있다.
let
let
은 단순히 변수를 선언하거나 shadowing하기 위한 것으로 인식하고 있었지만
이 녀석도 패턴과 유관하다.
let 패턴 = 표현식;
형태로 값이 대입되기 때문이다.
패턴으로 변수 이름 하나가 오면 그것은 어떤 값이든 담을 수 있기에 그대로 대입된다.
표현식의 결과값이 튜플일 경우 하나의 튜플 변수에 저장할 수도 있지만
다음과 같이 패턴을 통해 각각의 변수로 분할하여 해체할 수도 있다.
let (x, y, z) = (1, 2, 3);
물론 원소의 개수가 맞지 않다면 패턴이 일치하지 않아 컴파일되지 않는다.
만약 부분적으로만 사용하고 싶다면 자리지정자 _
를 통해 특정 값을 무시하거나
..
를 통해 특정 구간을 무시할 수 있다.
여기서 주의할 점은, _
는 여러 번 사용할 수 있지만
..
는 여러 번 사용하게 될 경우 어느 부분을 의미하는지 불명확해지므로 허용하지 않는다.
자리지정자는 원래 '어떤 값이든 매치됨'을 의미하지만
'어떤 값이 와도 신경쓰지 않겠다'의 의미로 사용되었다고 할 수 있겠다.
함수의 매개변수에도 패턴이 적용된다.
이것은 let
에서와 크게 다르지 않다.
매개변수가 x: i32
라면 그 어떤 i32 값이든 패턴에 일치하여 전달될 수 있다.
그리고 let
에서와 마찬가지로 패턴을 이용하여 튜플을 해체할 수 있다.
peter@hp-laptop:~/rust-practice/chapter18/for_example$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new parameter_example
Created binary (application) `parameter_example` package
peter@hp-laptop:~/rust-practice/chapter18$ cd parameter_example/
peter@hp-laptop:~/rust-practice/chapter18/parameter_example$ vi src/main.rs
src/main.rs
fn print_coordinates(&(x, y): &(i32, i32)) { println!("Current location: ({}, {})", x, y); } fn main() { let point = (3, 5); print_coordinates(&point); }
peter@hp-laptop:~/rust-practice/chapter18/parameter_example$ cargo run
Compiling parameter_example v0.1.0 (/home/peter/rust-practice/chapter18/parameter_example)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/parameter_example`
Current location: (3, 5)
peter@hp-laptop:~/rust-practice/chapter18/parameter_example$
이를 통해 인자로 전달할 땐 튜플로 받되,
함수에서 사용할 땐 튜플의 인덱스로 접근하는 게 아니라 개별 변수로 접근하도록 할 수 있다.
패턴은 크게 두 가지 부류로 나눌 수 있다.
부인할 수 있는Refutable 패턴과 부인할 수 없는Irrefutable 패턴.
let x = 5;
에서와 같이 주어진 모든 값에 일치하는 패턴을 부인할 수 없는 패턴이라고 한다.
반대로, match
문에서처럼 특정 값들에 대해서만 일치하는 패턴을 부인할 수 있는 패턴이라고 한다.
match
, if let
, while let
에서는 부인할 수 있는 패턴을 사용해야 한다.
부인할 수 없는 패턴을 사용해도 문제가 되지는 않지만 이걸 사용하는 의미가 없게 된다.
for
, let
, 매개변수에서는 부인할 수 없는 패턴을 사용해야 한다.
부인할 수 있는 패턴을 사용하게 될 경우 Rust 컴파일러가 컴파일을 거부할 것이다.
우리는 지금까지 패턴을 사용할 수 있는 상황들에 대해 알아보았다.
그렇다면 그 패턴 자체는 어떻게 생긴 녀석이어야 하는지 알아보도록 하자.
다음의 패턴 문법들은 모든 상황에서 다 가능한 건 아니고, 상황에 맞게 사용할 수 있다.
패턴으로 리터럴을 사용하여 리터럴과 어떤 값을 비교하도록 할 수 있다.
예를 들어, 다음과 같은 경우다.
peter@hp-laptop:~/rust-practice/chapter18/parameter_example$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new literal_match
Created binary (application) `literal_match` package
peter@hp-laptop:~/rust-practice/chapter18$ cd literal_match/
peter@hp-laptop:~/rust-practice/chapter18/literal_match$ vi src/main.rs
src/main.rs
fn main() { let x = 1; match x { 1 => println!("one"), 2 => println!("two"), 3 => println!("three"), _ => println!("anything"), } }
peter@hp-laptop:~/rust-practice/chapter18/literal_match$ cargo run
Compiling literal_match v0.1.0 (/home/peter/rust-practice/chapter18/literal_match)
Finished dev [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/literal_match`
one
peter@hp-laptop:~/rust-practice/chapter18/literal_match$
패턴에 열거형이 사용될 경우,
그 열거값이 포함하고 있는 개별 값에 대해서도 패턴을 설정할 수 있다.
예를 들어, Option
의 경우, Some
인 경우와 None
인 경우로 나눌 수도 있지만
Some(x)
의 x
에 적절한 값을 넣어
Some
이면서 특정 값을 가지고 있는 경우로 패턴을 설정할 수도 있다.
그리고 Some(x)
와 같이 변수를 넣을 경우, 이것은 그림자 변수로 사용된다.
그림자 변수는 패턴 매칭 내부에서만 사용되는 지역 변수와 같다.
외부에 같은 이름의 변수가 있어도 그것과는 별개로 사용되며
열거값에 포함되어 있는 값을 이 패턴과 연결된 표현식에서 사용할 수 있게 해준다.
다음은 그림자 변수가 포함된 match
표현식의 예시다.
peter@hp-laptop:~/rust-practice/chapter18/literal_match$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new shadow_match
Created binary (application) `shadow_match` package
peter@hp-laptop:~/rust-practice/chapter18$ cd shadow_match/
peter@hp-laptop:~/rust-practice/chapter18/shadow_match$
src/main.rs
fn main() { let x = Some(5); let y = 10; match x { Some(50) => println!("Got 50"), Some(y) => println!("Matched, y = {:?}", y), _ => println!("Default case, x = {:?}", x), } println!("at the end: x = {:?}, y = {:?}", x, y); }
peter@hp-laptop:~/rust-practice/chapter18/shadow_match$ cargo run
Compiling shadow_match v0.1.0 (/home/peter/rust-practice/chapter18/shadow_match)
Finished dev [unoptimized + debuginfo] target(s) in 0.34s
Running `target/debug/shadow_match`
Matched, y = 5
at the end: x = Some(5), y = 10
peter@hp-laptop:~/rust-practice/chapter18/shadow_match$
실제로 Some(y)
는 앞서 선언한 y
가 아니라 그림자 변수임을 확인할 수 있다.
그리고 match
문을 벗어난 후의 y
는 다시 앞서 선언한 y
가 출력된다.
여러 개의 패턴에 대한 실행 표현식이 동일하다면 해당 패턴들을 묶어서 다중 패턴으로 사용할 수 있다.
이 때, 각각의 패턴은 |
로 구분된다.
이것은 OR 연산으로, 해당 패턴들 중 하나라도 일치하면 일치하는 것으로 취급한다.
다중 패턴은 다음과 같이 사용할 수 있다.
peter@hp-laptop:~/rust-practice/chapter18/shadow_match$ cd ..peter@hp-laptop:~/rust-practice/chapter18$ cargo new multiple_patterns
Created binary (application) `multiple_patterns` package
peter@hp-laptop:~/rust-practice/chapter18$ cd multiple_patterns/
peter@hp-laptop:~/rust-practice/chapter18/multiple_patterns$ vi src/main.rs
src/main.rs
fn main() { let x = 1; match x { 1 | 2 => println!("one or two"), 3 => println!("three"), _ => println!("anything"), } }
peter@hp-laptop:~/rust-practice/chapter18/multiple_patterns$ cargo run
Compiling multiple_patterns v0.1.0 (/home/peter/rust-practice/chapter18/multiple_patterns)
Finished dev [unoptimized + debuginfo] target(s) in 0.19s
Running `target/debug/multiple_patterns`
one or two
peter@hp-laptop:~/rust-practice/chapter18/multiple_patterns$
x
의 값을 2로 변경해도 같은 결과가 나온다.
만약 연속된 일련의 값을 다중 패턴으로 사용하고 싶다면 ..=
을 사용할 수 있다.
예를 들어, 1 | 2 | 3 | 4 | 5
라고 쓸 것을 1 ..= 5
라고 할 수 있다는 것이다.
// 예전에는 ...로 사용했기에 오래된 자료에는 ...로 나와 있을 수 있다.
다만, 이것은 정수와 문자에서만 사용할 수 있다.
match
문을 사용할 때 컴파일러가 커버되지 않는 값이 있는지 검사하는데
범위가 비어있는지 판단 가능한 것이 이들 뿐이기 때문이다.
앞에서 let
과 매개변수에서 패턴을 사용하는 것을 살펴볼 때 이미 확인했지만
묶여 있는 값을 패턴을 이용하여 해체할 수 있다.
우리는 튜플을 해체하는 것만 해봤지만 구조체를 해체하는 것도 크게 다르지 않다.
peter@hp-laptop:~/rust-practice/chapter18/multiple_patterns$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new destructure_struct
Created binary (application) `destructure_struct` package
peter@hp-laptop:~/rust-practice/chapter18$ cd destructure_struct/
peter@hp-laptop:~/rust-practice/chapter18/destructure_struct$ vi src/main.rs
src/main.rs
struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; let Point { x: a, y: b } = p; assert_eq!(0, a); assert_eq!(7, b); }
peter@hp-laptop:~/rust-practice/chapter18/destructure_struct$ cargo run
Compiling destructure_struct v0.1.0 (/home/peter/rust-practice/chapter18/destructure_struct)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/destructure_struct`
peter@hp-laptop:~/rust-practice/chapter18/destructure_struct$
만약 구조체의 필드와 같은 이름을 가진 변수를 사용하면 이보다 더 단순하게 사용할 수도 있다.
필드와 변수의 이름이 같다면 let Point { x, y } = p;
와 같이 사용할 수 있다.
혹은, 이것을 변수에 대입하지 않고 바로 match
문으로 연결할 수도 있다.
peter@hp-laptop:~/rust-practice/chapter18/destructure_struct$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new destructure_match Created binary (application) `destructure_match` package
peter@hp-laptop:~/rust-practice/chapter18$ cd destructure_match/
peter@hp-laptop:~/rust-practice/chapter18/destructure_match$ vi src/main.rs
src/main.rs
struct Point { x :i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; match p { Point { x, y: 0 } => println!("On the x axis at {}", x), Point { x: 0, y } => println!("On the y axis at {}", y), Point { x, y } => println!("On neigher axis: ({}, {})", x, y), } }
peter@hp-laptop:~/rust-practice/chapter18/destructure_match$ cargo run
Compiling destructure_match v0.1.0 (/home/peter/rust-practice/chapter18/destructure_match)
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
Running `target/debug/destructure_match`
On the y axis at 7
또한, 패턴을 통해 열거형도 해체할 수 있는데
열거형의 경우 각각의 열거값을 패턴으로 하여 match
문을 작성할 수 있다.
그리고 그 match
문의 arm에서 해당 패턴에 대한 값 해체가 이루어진다.
peter@hp-laptop:~/rust-practice/chapter18/destructure_match$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new destructure_enum
Created binary (application) `destructure_enum` package
peter@hp-laptop:~/rust-practice/chapter18$ cd destructure_enum/
peter@hp-laptop:~/rust-practice/chapter18/destructure_enum$ vi src/main.rs
src/main.rs
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), } }
peter@hp-laptop:~/rust-practice/chapter18/destructure_enum$ cargo run
Compiling destructure_enum v0.1.0 (/home/peter/rust-practice/chapter18/destructure_enum)
# snip warnings
Finished dev [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/destructure_enum`
Change the color to red 0, green 160, and blue 255
peter@hp-laptop:~/rust-practice/chapter18/destructure_enum$
각각의 열거값마다 포함하고 있는 값들의 구성이 서로 다를 수 있기 때문에
반드시 이렇게 열거값에 따른 패턴 매칭 후에 각각의 경우에 대해 해체해주어야 한다.
만약 열거형 안에 열거형이 중첩되어 있다면
외부 열거형을 열거값으로 패턴 매칭 후 그 표현식에서 내부 열거형을 열거값으로 패턴매칭하거나
애초부터 외부열거값(내부열거값)
을 패턴으로 사용할 수 있다.
앞서 몇 번 언급된 바가 있지만 자리지정자 _
를 통해 패턴의 일부를 무시할 수 있다.
그리고 ..
를 통해 어떤 값 이전 전체, 어떤 값 이후 전체,
혹은 어떤 두 값 사이를 범위째 무시할 수 있다는 것과
그것을 두 번 이상 사용할 경우 어느 부분을 나타내는지 모호해져서 최대 한 번만 가능함도 배웠다.
자리지정자를 사용하면 값을 바인딩하지도 않고 무시하지만
변수 이름을 정한 채 그 앞에 _
를 붙이면 값을 바인딩한 채 그것을 무시하게 된다.
이것이 왜 필요한가 싶을 수 있는데,
Rust는 변수를 선언해놓고 사용하지 않으면 경고를 띄운다.
그런데 때로는 코드의 프로토타입에서 나중에 사용할 변수를 선언해두었지만
아직은 사용하지 않은 상황이 있을 수 있다.
이런 상황에서 우리는 불필요한 경고 없이 컴파일 결과를 확인하기 위해 임시로 _
를 붙일 수 있다.
물론 개발이 완료되면 앞에 _
가 붙은 변수는 더이상 남지 않을 것이다.
매치 가드는 패턴을 보완하여 추가적인 조건을 설정하는 데 사용된다.
이것을 사용하면 패턴만으로는 표현할 수 없는, 보다 복잡한 조건의 매칭이 가능하다.
예를 들어, 패턴만으로는 값의 범위를 제한할 수 없지만
매치 가드를 사용하면 다음과 같이 작성할 수 있다.
peter@hp-laptop:~/rust-practice/chapter18/destructure_enum$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new match_guard
Created binary (application) `match_guard` package
peter@hp-laptop:~/rust-practice/chapter18$ cd match_guard/
peter@hp-laptop:~/rust-practice/chapter18/match_guard$ vi src/main.rs
src/main.rs
fn main() { let num = Some(4); match num { Some(x) if x < 5 => println!("less than five: {}", 4), Some(x) => println!("{}", x), None => (), } }
peter@hp-laptop:~/rust-practice/chapter18/match_guard$ cargo run
Compiling match_guard v0.1.0 (/home/peter/rust-practice/chapter18/match_guard)
Finished dev [unoptimized + debuginfo] target(s) in 0.26s
Running `target/debug/match_guard`
less than five: 4
peter@hp-laptop:~/rust-practice/chapter18/match_guard$
또한, 매치 가드를 사용하면 match
문 밖의 값과의 비교 연산도 가능하다.
peter@hp-laptop:~/rust-practice/chapter18/match_guard$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new match_guard_outer
Created binary (application) `match_guard_outer` package
peter@hp-laptop:~/rust-practice/chapter18$ cd match_guard_outer/
peter@hp-laptop:~/rust-practice/chapter18/match_guard_outer$ vi src/main.rs
src/main.rs
fn main() { let x = Some(5); let y = 10; match x { Some(50) => println!("50"), Some(n) if n == y => println!("Matched, n = {}", n), _ => println!("Default case, x = {:?}", x), } println!("at the end: x = {:?}, y = {}", x, y); }
peter@hp-laptop:~/rust-practice/chapter18/match_guard_outer$ cargo run
Compiling match_guard_outer v0.1.0 (/home/peter/rust-practice/chapter18/match_guard_outer)
Finished dev [unoptimized + debuginfo] target(s) in 0.21s
Running `target/debug/match_guard_outer`
Default case, x = Some(5)
at the end: x = Some(5), y = 10
peter@hp-laptop:~/rust-practice/chapter18/match_guard_outer$
매치 가드는 패턴과는 달리 새로운 변수를 생성하지 않고
패턴이 만든 그림자 변수나 외부 변수를 사용한다.
다중 패턴에 매치 가드를 적용할 경우 다중 패턴 모두에 매치 가드가 적용된다.
만약 다중 패턴을 사용하면서 그 중 특정 값에만 적용하고 싶다면
4 | 5 | (6 if y)
와 같이 괄호로 묶어주어야 한다.
@
바인딩@
연산자를 사용하면 패턴 일치 여부를 확인하면서 그 값을 가진 변수를 생성할 수 있다.
이 변수는 해당 arm의 표현식에서 사용할 수 있다.
패턴 앞에 변수 @
을 붙여서 사용한다.
다음은 @
바인딩을 사용하는 예제다.
peter@hp-laptop:~/rust-practice/chapter18/match_guard_outer$ cd ..
peter@hp-laptop:~/rust-practice/chapter18$ cargo new at_binding
Created binary (application) `at_binding` package
peter@hp-laptop:~/rust-practice/chapter18$ cd at_binding/
peter@hp-laptop:~/rust-practice/chapter18/at_binding$ vi src/main.rs
src/main.rs
enum Message { Hello { id: i32 }, } fn main() { 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), } }
peter@hp-laptop:~/rust-practice/chapter18/at_binding$ cargo run
Compiling at_binding v0.1.0 (/home/peter/rust-practice/chapter18/at_binding)
Finished dev [unoptimized + debuginfo] target(s) in 0.19s
Running `target/debug/at_binding`
Found an id in range: 5
peter@hp-laptop:~/rust-practice/chapter18/at_binding$
Some(x)
와 같이 그것이 가진 모든 값을 저장하여 표현식에서 x
를 사용할 수 있다면
@
바인딩이 필요하지 않지만
열거형에 대한 match
문에서 열거형 자체가 아닌 세부 패턴으로 조건을 제시해서
그 열거형 자체에 대한 참조가 불가능할 때 @
바인딩이 유용하다.
패턴과 매칭은 이렇게 다양한 영역에서 다양하게 활용될 수 있다.
이것을 충분히 활용할 수 있게 되면 Rust를 보다 유연하게 사용할 수 있게 될 것이다.
이 포스트의 내용은 공식문서의 18장 Patterns and Matching에 해당합니다.