패턴 (pattern)
복잡하거나 단순한 타입의 구조와 매칭을 위한 러스트의 특수 문법
패턴을 match 표현 및 기타 구문과 함께 사용하면 프로그램 흐름을 더 잘 제어할 수 있음
패턴을 이용하기 위해서는 그 패턴을 어떤 값에 비교하는데, 패턴이 값에 매칭되면 코드에서 값 부분을 사용함
- 패턴의 구성
리터럴 값
해체한(destructured) 배열, 열거형, 구조체, 튜플
변수
와일드카드
자리표시자
match 갈래
// match VALUE {
// PATTERN => EXPRESSION,
// PATTERN => EXPRESSION,
// }
match x {
None => None,
Some(i) => Some(i + 1),
}
패턴은 match 표현식에서 갈래로 사용됨
match 표현식의 한 가지 요건은 match 표현식의 값에 대한 모든 경우의 수를 고려해야 한다는 의미에서 철저해야(exhaustive) 한다는 것임
모든 가능성을 포괄하는 것을 보장하는 방법 중 한 가지는 마지막 갈래에 포괄패턴(_)을 사용하는 것임
if let 조건 표현식
match를 짧게 작성하는 방법으로 if let, else if, else if let 표현식을 섞어서 매칭할 수 있음
패턴과 비교할 값을 하나만 표현할 수 있는 match 표현식 보다 더 유연하게 사용할 수 있음
그리고 러스트에서는 각 갈래들의 조건식이 서로 연관될 필요도 없음
while let 조건 루프
if let 구조와 비슷한 while let 조건 루프는 패턴이 계속 매칭되는 동안 while 루프를 실행할 수 있게 해줌
for 루프
for 루프에서 바로 뒤에 오는 것은 패턴임 (for x in y에서 x가 패턴)
let 구문
// let PATTERN = EXPRESSION;
let x = 5;
let (x, y, z) = (1, 2, 3);
let 구문 또한 패턴을 사용하는 것임
let x = 5는 이 패턴에 매칭되는 값을 변수 x에 대입하라는 의미임
함수 매개변수
fn foo(x: i32) {
// do somthing
}
함수 매개변수도 패턴임
반박 가능성
패턴에는 반박 가능한 패턴과 반박 불가능한 패턴이 있음
- 반박 불가능한 패턴 (irrefutable)
반박 불가능한 패턴은 넘겨진 모든 가능한 값에 대해 매칭되는 패턴임
일례로 let x = 5; 구문에서 x는 무엇이든 매칭되므로 매칭에 실패할 수 없음
- 반박 가능한 패턴 (refutable)
이와 반대로 일부 가능한 값에 대해 매칭에 실패할 수 있는 패턴은 반박 가능한 패턴임
Some(x) 표현식에서 x가 None이면 패턴 매칭이 되지 않음
함수 매개변수, let 구문 및 for 루프에는 반박 불가능한 패턴만 허용될 수 있는데,
이는 매칭되지 않으면 프로그램이 의미있는 작업을 수행할 수 없기 때문
if let과 while let 표현식은 반박 가능한 패턴과 반박 불가능한 패턴을 허용하지만
컴파일러는 반박 불가능한 패턴에 대해 경고를 줌 (이 표현식들이 잠재적인 실패를 처리할 목적으로 만들어졌기 때문)
패턴 문법
리터럴 매칭
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anthing"),
}
명명된 변수매칭
명명된 변수는 어떤 값과도 매칭되는 반박 불가능한 패턴
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("got 50"),
Some(y) => println!("match y {y}"),
_ => println!("default {:?}", x),
}
println!("end x = {:?}, y = {:?}", x, y);
}
다중 패턴
match 표현식에서는 패턴에 대한 또는(or) 연산자인 | 문법을 사용하여 여러 패턴을 매칭시킬 수 있음
fn main() {
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anthing"),
}
}
// result
// one or two
..=을 이용한 값의 범위 매칭
..= 문법은 경계 값을 포함하는 범위와 매칭시켜줌
fn main() {
let x= 5;
match x {
1..=5 => println!("one through five"), // 1, 2, 3, 4, 5 중 하나에 매칭
_ => println!("something else"),
}
}
값을 해체하여 분리하기
구조체 분리하기
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); // true
assert_eq!(7, b); // true
}
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("x = {x}"),
Point { x: 0, y } => println!("y = {y}"), // true
Point { x, y } => println!("x = {x}, y = {y}"),
}
}
열거형 해체하기
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::ChangeColor(r, g, b) => println!("red {r}, green {g}, blue {b}"),
}
}
중첩된 구조체와 열거형 해체하기
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChagneColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!("hue {h}, saturation {s}, value {v}")
}
_ => (),
}
}
구조체와 튜플 해체하기
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
패턴에서 값 무시하기
패턴에서 값의 전체 또는 일부를 무사히는 방법은 여러가지가 있음
- _ 패턴 사용하기
- 다른 패턴 내에서 _ 패턴 사용하기
- 밑줄로 시작하는 이름 사용하기
- ..을 사용하여 값의 나머지 부분을 무시하기
_로 전체 무시하기
fn foo(_: i32, y: i32) {
println!("only y {}", y);
}
fn main() {
foo(3, 4);
}
중첩된 _로 값의 일부 무시하기
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 customize value"); // true
}
_ => {
setting_value = new_setting_value;
}
}
println!("setting is {:?}", setting_value); // setting is Some(5)
}
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("{first}, {third}, {fifth}");
}
}
}
_로 시작하는 이름으로 사용하지 않는 변수 무시하기
fn main() {
let _x = 5;
let y = 10;
}
..으로 값의 나머지 부분 무시하기
struct Point {
x: i32,
y: i32,
z: i32,
}
fn main() {
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
Point {x, .. } => println!("x is {}", x),
}
}
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, .., last) => {
println!("{first}, {last}");
}
}
}
매치 카드를 사용한 추가 조건
매치 가드(match guard)는 match 갈래의 패턴 뒤에 지정되는 추가 if 조건으로, 해당 갈래가 선택되려면 이 조건도 매칭되어야함
매치 가드는 패턴만 가지고는 할 수 없는 더 복잡한 아이디어를 표현할 때 유용
fn main() {
let Some(4);
match num {
Some(x) if x % 2 === 0 => println!("number is even {}", x), // true
Some(x) => println!("number is odd"),
None => (),
}
}
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(n) if n == y => println!("Matched n = {}", n),
_ => println!("Default case x = {:?}", x), // true. n은 섀도잉 y는 외부변수
}
}
fn main() {
let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("yes"), // true. 4 | 5 | (6 if y)
_ => println!("no"),
}
}
@ 바인딩
at 연산자 @을 사용하면 값에 대한 패턴 매칭 여부를 테스트하는 동시에 해당 값을 갖는 변수를 만들 수 있음
enum Message {
Hello { id: i32 },
}
fn main() {
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: id_variable @ 3..7,
} => println!("Found am id in range {}", id_variable), // true. id_variable에 @을 지정하여 3~7 범위에 매칭되는 어떤 값이든 캡처
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message::Hello { id } => println!("Found same id: {}", id),
}
}
'Programming > Rust' 카테고리의 다른 글
| 러스트 고급 트레이트 (0) | 2025.10.12 |
|---|---|
| 안전하지 않은 러스트 (0) | 2025.10.12 |
| 러스트의 객체 지향 프로그래밍 기능 (0) | 2025.10.11 |
| 러스트 동시성 (0) | 2025.10.09 |
| 러스트 스마트 포인터 (0) | 2025.10.09 |
