다음을 통해 공유


패턴 일치

패턴은 입력 데이터를 변환하기 위한 규칙입니다. F# 전체에서 논리 구조 또는 구조와 데이터를 비교하거나, 데이터를 구성 요소로 분해하거나, 다양한 방법으로 데이터에서 정보를 추출하는 데 사용됩니다.

발언

패턴은 match 식과 같은 많은 언어 구문에서 사용됩니다. let 바인딩, 람다 식 및 try...with 식과 연결된 예외 처리기에서 함수에 대한 인수를 처리할 때 사용됩니다. 자세한 내용은 일치 식, let 바인딩, 람다 식: fun 키워드예외: try...with를 참조하세요.

예를 들어 match 식에서 패턴 파이프 기호 뒤에 있습니다.

match expression with
| pattern [ when condition ] -> result-expression
...

각 패턴은 어떤 식으로든 입력을 변환하는 규칙으로 작동합니다. match 식에서 각 패턴을 차례로 검사하여 입력 데이터가 패턴과 호환되는지 확인합니다. 일치 항목이 발견되면 결과 식이 실행됩니다. 일치 항목을 찾을 수 없으면 다음 패턴 규칙이 테스트됩니다. 조건 부분은 일치 식에서 설명될 때 선택 사항입니다.

지원되는 패턴은 다음 표에 나와 있습니다. 런타임에 입력은 테이블에 나열된 순서에서 다음 패턴 각각에 대해 테스트되며, 패턴은 코드에 표시되는 첫 번째 패턴에서 마지막까지, 각 줄의 패턴에 대해 왼쪽에서 오른쪽으로 재귀적으로 적용됩니다.

이름 묘사 본보기
상수 패턴 숫자, 문자 또는 문자열 리터럴, 열거형 상수 또는 정의된 리터럴 식별자 1.0, "test", 30, Color.Red
식별자 패턴 구별된 유니온의 경우 값, 예외 레이블 또는 활성 패턴의 경우 Some(x)

Failure(msg)
가변 패턴 식별자 a
as 패턴 패턴식별자 (a, b) as tuple1
OR 패턴 pattern1 | pattern2 ([h] | [h; _])
AND 패턴 패턴1 & 패턴2 (a, b) & (_, "test")
단점 패턴 식별자 :: 목록 식별자 h :: t
목록 패턴 [ pattern_1; ... ; pattern_n ] [ a; b; c ]
배열 패턴 [| pattern_1; ..; pattern_n |] [| a; b; c |]
괄호로 묶인 패턴 ( 패턴 ) ( a )
튜플 패턴 ( pattern_1, ... , pattern_n ) ( a, b )
레코드 패턴 { identifier1 = pattern_1; ... ; identifier_n = pattern_n } { Name = name; }
와일드카드 패턴 _ _
패턴과 형식 주석 함께하기 패턴 : 형식 a : int
타입 테스트 패턴 :? 형식 [ 식별자로서 ] :? System.DateTime as dt
Null 패턴 null
이름의 패턴 표현 이름 nameof str

상수 패턴

상수 패턴은 숫자, 문자 및 문자열 리터럴, 열거형 상수입니다(열거형 형식 이름이 포함됨). 상수 패턴만 있는 match 식은 다른 언어의 case 문과 비교할 수 있습니다. 입력은 리터럴 값과 비교되며 값이 같으면 패턴이 일치합니다. 리터럴의 형식은 입력 형식과 호환되어야 합니다.

다음 예제에서는 리터럴 패턴의 사용을 보여 줍니다. 또한 변수 패턴 및 OR 패턴을 사용합니다.

[<Literal>]
let Three = 3

let filter123 x =
    match x with
    // The following line contains literal patterns combined with an OR pattern.
    | 1 | 2 | Three -> printfn "Found 1, 2, or 3!"
    // The following line contains a variable pattern.
    | var1 -> printfn "%d" var1

for x in 1..10 do filter123 x

리터럴 패턴의 또 다른 예는 열거형 상수에 기반한 패턴입니다. 열거형 상수를 사용하는 경우 열거형 형식 이름을 지정해야 합니다.

type Color =
    | Red = 0
    | Green = 1
    | Blue = 2

let printColorName (color:Color) =
    match color with
    | Color.Red -> printfn "Red"
    | Color.Green -> printfn "Green"
    | Color.Blue -> printfn "Blue"
    | _ -> ()

printColorName Color.Red
printColorName Color.Green
printColorName Color.Blue

식별자 패턴

패턴이 유효한 식별자를 형성하는 문자 문자열인 경우 식별자 형식에 따라 패턴이 일치하는 방법이 결정됩니다. 식별자가 단일 문자보다 길고 대문자로 시작하는 경우 컴파일러는 식별자 패턴과 일치시키려고 시도합니다. 이 패턴의 식별자는 리터럴 특성, 구분된 공용 구조체 사례, 예외 식별자 또는 활성 패턴 사례로 표시된 값일 수 있습니다. 일치하는 식별자를 찾을 수 없으면 일치가 실패하고 다음 패턴 규칙인 변수 패턴이 입력과 비교됩니다.

식별된 유니온 패턴은 단순한 명명된 경우일 수도 있고, 하나의 값 또는 여러 값을 포함하는 튜플일 수도 있습니다. 값이 있는 경우 값의 식별자를 지정해야 합니다. 튜플의 경우 튜플의 각 요소에 대한 식별자가 있는 튜플 패턴을 제공하거나 하나 이상의 명명된 공용 구조체 필드에 대한 필드 이름을 가진 식별자를 제공해야 합니다. 예제는 이 섹션의 코드 예제를 참조하세요.

option 형식은 SomeNone두 가지 사례가 있는 차별된 공용 구조체입니다. 한 사례(Some)에는 값이 있지만 다른 사례(None)는 명명된 사례일 뿐입니다. 따라서 SomeSome 사례와 연결된 값에 대한 변수가 있어야 하지만 None 그 자체로 나타나야 합니다. 다음 코드에서 변수 var1Some 사례와 일치하여 얻은 값이 제공됩니다.

let printOption (data : int option) =
    match data with
    | Some var1  -> printfn "%d" var1
    | None -> ()

다음 예제에서 PersonName 구별된 유니온에는 이름의 가능한 형식을 나타내는 문자열과 문자가 혼합되어 있습니다. 차별된 공용 구조체의 경우는 FirstOnly, LastOnlyFirstLast.

type PersonName =
    | FirstOnly of string
    | LastOnly of string
    | FirstLast of string * string

let constructQuery personName =
    match personName with
    | FirstOnly(firstName) -> printf "May I call you %s?" firstName
    | LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
    | FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName

명명된 필드가 있는 구분된 공용 구조체의 경우 등호(=)를 사용하여 명명된 필드의 값을 추출합니다. 예를 들어 다음과 같은 선언이 있는 판별된 합집합을 고려하십시오.

type Shape =
    | Rectangle of height : float * width : float
    | Circle of radius : float

다음과 같이 패턴 일치 식에서 명명된 필드를 사용할 수 있습니다.

let matchShape shape =
    match shape with
    | Rectangle(height = h) -> printfn $"Rectangle with length %f{h}"
    | Circle(r) -> printfn $"Circle with radius %f{r}"

명명된 필드의 사용은 선택 사항이므로 이전 예제에서는 Circle(r)Circle(radius = r) 모두 동일한 효과를 갖습니다.

여러 필드를 지정할 때 세미콜론(;)을 구분 기호로 사용합니다.

match shape with
| Rectangle(height = h; width = w) -> printfn $"Rectangle with height %f{h} and width %f{w}"
| _ -> ()

활성 패턴을 사용하면 더 복잡한 사용자 지정 패턴 일치를 정의할 수 있습니다. 활성 패턴에 대한 자세한 내용은 활성 패턴참조하세요.

식별자가 예외인 경우 예외 처리기의 컨텍스트에서 패턴 일치에 사용됩니다. 예외 처리의 패턴 일치에 대한 자세한 내용은 예외: try...with참조하세요.

변수 패턴

변수 패턴은 일치하는 값을 변수 이름에 할당한 다음 -> 기호의 오른쪽에 있는 실행 식에서 사용할 수 있습니다. 변수 패턴만으로도 모든 입력과 일치하지만 변수 패턴은 종종 다른 패턴 내에 표시되므로 튜플 및 배열과 같은 더 복잡한 구조체를 변수로 분해할 수 있습니다.

다음 예제에서는 튜플 패턴 내의 변수 패턴을 보여 줍니다.

let function1 x =
    match x with
    | (var1, var2) when var1 > var2 -> printfn "%d is greater than %d" var1 var2
    | (var1, var2) when var1 < var2 -> printfn "%d is less than %d" var1 var2
    | (var1, var2) -> printfn "%d equals %d" var1 var2

function1 (1,2)
function1 (2, 1)
function1 (0, 0)

패턴으로

as 패턴은 as 절이 추가된 패턴입니다. as 절은 일치하는 값을 match 식의 실행 식에 사용할 수 있는 이름에 바인딩하거나, 이 패턴이 let 바인딩에서 사용되는 경우 이름이 로컬 범위에 바인딩으로 추가됩니다.

다음 예제에서는 as 패턴을 사용합니다.

let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1

또는 패턴

OR 패턴은 입력 데이터가 여러 패턴과 일치할 수 있고 결과와 동일한 코드를 실행하려는 경우에 사용됩니다. OR 패턴의 양면 형식은 호환되어야 합니다.

다음 예제에서는 OR 패턴을 보여 줍니다.

let detectZeroOR point =
    match point with
    | (0, 0) | (0, _) | (_, 0) -> printfn "Zero found."
    | _ -> printfn "Both nonzero."
detectZeroOR (0, 0)
detectZeroOR (1, 0)
detectZeroOR (0, 10)
detectZeroOR (10, 15)

AND 패턴

AND 패턴을 사용하려면 입력이 두 패턴과 일치해야 합니다. AND 패턴의 양면 형식은 호환되어야 합니다.

다음 예제는 이 항목의 뒷부분에 있는 튜플 패턴 섹션에 표시된 detectZeroTuple 같지만 여기서는 var1var2 모두 AND 패턴을 사용하여 값으로 가져옵니다.

let detectZeroAND point =
    match point with
    | (0, 0) -> printfn "Both values zero."
    | (var1, var2) & (0, _) -> printfn "First value is 0 in (%d, %d)" var1 var2
    | (var1, var2)  & (_, 0) -> printfn "Second value is 0 in (%d, %d)" var1 var2
    | _ -> printfn "Both nonzero."
detectZeroAND (0, 0)
detectZeroAND (1, 0)
detectZeroAND (0, 10)
detectZeroAND (10, 15)

단점 패턴

컨스 패턴은 목록을 첫 번째 요소인 헤드와 나머지 요소를 포함하는 목록인 테일로 분해하는 데 사용됩니다.

let list1 = [ 1; 2; 3; 4 ]

// This example uses a cons pattern and a list pattern.
let rec printList l =
    match l with
    | head :: tail -> printf "%d " head; printList tail
    | [] -> printfn ""

printList list1

목록 패턴

목록 패턴을 사용하면 목록을 여러 요소로 분해할 수 있습니다. 목록 패턴 자체는 특정 개수의 요소 목록만 일치시킬 수 있습니다.

// This example uses a list pattern.
let listLength list =
    match list with
    | [] -> 0
    | [ _ ] -> 1
    | [ _; _ ] -> 2
    | [ _; _; _ ] -> 3
    | _ -> List.length list

printfn "%d" (listLength [ 1 ])
printfn "%d" (listLength [ 1; 1 ])
printfn "%d" (listLength [ 1; 1; 1; ])
printfn "%d" (listLength [ ] )

배열 패턴

배열 패턴은 목록 패턴과 유사하며 특정 길이의 배열을 분해하는 데 사용할 수 있습니다.

// This example uses array patterns.
let vectorLength vec =
    match vec with
    | [| var1 |] -> var1
    | [| var1; var2 |] -> sqrt (var1*var1 + var2*var2)
    | [| var1; var2; var3 |] -> sqrt (var1*var1 + var2*var2 + var3*var3)
    | _ -> failwith (sprintf "vectorLength called with an unsupported array size of %d." (vec.Length))

printfn "%f" (vectorLength [| 1. |])
printfn "%f" (vectorLength [| 1.; 1. |])
printfn "%f" (vectorLength [| 1.; 1.; 1.; |])
printfn "%f" (vectorLength [| |] )

괄호로 감싼 패턴

괄호는 원하는 결합성을 달성하기 위해 패턴을 중심으로 그룹화할 수 있습니다. 다음 예제에서 괄호는 AND 패턴과 단점 패턴 간의 결합성을 제어하는 데 사용됩니다.

let countValues list value =
    let rec checkList list acc =
       match list with
       | (elem1 & head) :: tail when elem1 = value -> checkList tail (acc + 1)
       | head :: tail -> checkList tail acc
       | [] -> acc
    checkList list 0

let result = countValues [ for x in -10..10 -> x*x - 4 ] 0
printfn "%d" result

튜플 패턴

튜플 패턴은 튜플 형식의 입력과 일치하며 튜플의 각 위치에 대해 패턴 일치 변수를 사용하여 튜플을 해당 구성 요소로 분해할 수 있습니다.

다음 예제에서는 튜플 패턴을 보여 줍니다. 리터럴 패턴, 변수 패턴 및 와일드카드 패턴도 사용합니다.

let detectZeroTuple point =
    match point with
    | (0, 0) -> printfn "Both values zero."
    | (0, var2) -> printfn "First value is 0 in (0, %d)" var2
    | (var1, 0) -> printfn "Second value is 0 in (%d, 0)" var1
    | _ -> printfn "Both nonzero."
detectZeroTuple (0, 0)
detectZeroTuple (1, 0)
detectZeroTuple (0, 10)
detectZeroTuple (10, 15)

레코드 패턴

레코드 패턴은 레코드를 분해하여 필드 값을 추출하는 데 사용됩니다. 패턴이 레코드의 모든 필드를 참조할 필요는 없습니다. 생략된 필드는 일치에 참여하지 않고 추출되지 않습니다.

// This example uses a record pattern.

type MyRecord = { Name: string; ID: int }

let IsMatchByName record1 (name: string) =
    match record1 with
    | { MyRecord.Name = nameFound; MyRecord.ID = _; } when nameFound = name -> true
    | _ -> false

let recordX = { Name = "Parker"; ID = 10 }
let isMatched1 = IsMatchByName recordX "Parker"
let isMatched2 = IsMatchByName recordX "Hartono"

와일드카드 패턴

와일드카드 패턴은 밑줄(_) 문자로 표현되며 변수 패턴과 마찬가지로 모든 입력과 일치합니다. 단, 입력은 변수에 할당되지 않고 삭제됩니다. 와일드카드 패턴은 종종 다른 패턴 내에서 -> 기호 오른쪽의 식에 필요하지 않은 값의 자리 표시자로 사용됩니다. 와일드카드 패턴은 종종 패턴 목록의 끝에 사용되어 아직 일치하지 않은 입력을 매칭합니다. 와일드카드 패턴은 이 항목의 많은 코드 예제에서 보여 줍니다. 한 가지 예제는 위의 코드를 참조하세요.

형식 주석이 있는 패턴

패턴에는 형식 주석이 있을 수 있습니다. 이러한 주석은 다른 형식 주석과 같이 동작하며 다른 형식 주석과 같이 유추를 안내합니다. 패턴의 형식 주석에는 괄호가 필요합니다. 다음 코드는 형식 주석이 있는 패턴을 보여 줍니다.

let detect1 x =
    match x with
    | 1 -> printfn "Found a 1!"
    | (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1

타입 테스트 패턴

형식 테스트 패턴은 입력과 형식을 일치시킬 때 사용됩니다. 입력 형식이 패턴에 지정된 형식과 일치(또는 파생 형식)이면 일치가 성공합니다.

다음 예제에서는 형식 테스트 패턴을 보여 줍니다.

open System.Windows.Forms

let RegisterControl(control:Control) =
    match control with
    | :? Button as button -> button.Text <- "Registered."
    | :? CheckBox as checkbox -> checkbox.Text <- "Registered."
    | _ -> ()

식별자가 특정 파생 형식인지만 확인하는 경우 다음 예제와 같이 패턴의 as identifier 부분이 필요하지 않습니다.

type A() = class end
type B() = inherit A()
type C() = inherit A()

let m (a: A) =
    match a with
    | :? B -> printfn "It's a B"
    | :? C -> printfn "It's a C"
    | _ -> ()

Null 패턴

null 패턴은 null 값을 허용하는 형식으로 작업할 때 나타날 수 있는 null 값과 일치합니다. Null 패턴은 .NET Framework 코드와 상호 운용할 때 자주 사용됩니다. 예를 들어 .NET API의 반환 값은 match 식에 대한 입력일 수 있습니다. 반환 값이 null인지 여부와 반환된 값의 다른 특성에 따라 프로그램 흐름을 제어할 수 있습니다. null 패턴을 사용하여 null 값이 프로그램의 나머지 부분에 전파되지 않도록 방지할 수 있습니다.

다음 예제에서는 null 패턴과 변수 패턴을 사용합니다.

let ReadFromFile (reader : System.IO.StreamReader) =
    match reader.ReadLine() with
    | null -> printfn "\n"; false
    | line -> printfn "%s" line; true

let fs = System.IO.File.Open("..\..\Program.fs", System.IO.FileMode.Open)
let sr = new System.IO.StreamReader(fs)
while ReadFromFile(sr) = true do ()
sr.Close()

Null 패턴은 F# 9의 null 허용 여부 기능에도 권장됩니다.

let len (str: string | null) =
    match str with
    | null -> -1
    | s -> s.Length

마찬가지로, 새로운 널러빌리티 관련 전용 패턴을 사용할 수 있습니다.

let let str =       // str is inferred to be `string | null`
    match str with
    | Null -> -1
    | NonNull (s: string) -> s.Length

Nameof 패턴

nameof 패턴은 해당 값이 nameof 키워드 뒤에 있는 식과 같을 때 문자열과 일치합니다. 예를 들어:

let f (str: string) =
    match str with
    | nameof str -> "It's 'str'!"
    | _ -> "It is not 'str'!"

f "str" // matches
f "asdf" // does not match

이름을 사용할 수 있는 항목에 대한 자세한 내용은 nameof 연산자를 참조하세요.

참고 항목