패턴 일치

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

설명

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

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

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

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

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

이름 설명 예시
상수 패턴 숫자, 문자 또는 문자열 리터럴, 열거형 상수 또는 정의된 리터럴 식별자 1.0, "test", 30Color.Red
식별자 패턴 구분된 공용 구조체의 사례 값, 예외 레이블 또는 활성 패턴 사례 Some(x)

Failure(msg)
변수 패턴 identifier a
as 패턴 패턴 식별 (a, b) as tuple1
OR 패턴 pattern1 | pattern2 ([h] | [h; _])
AND 패턴 pattern1pattern2 (a, b) & (_, "test")
단점 패턴 identifier :: list-identifier 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; }
와일드카드 패턴 _ _
형식 주석과 함께 패턴 pattern : type a : int
형식 테스트 패턴 :? type [ as identifier ] :? System.DateTime as dt
Null 패턴 null null
Nameof 패턴 nameof expr 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 두 가지 사례가 있는 구분된 공용 구조체이며 None. Some 한 사례(Some)에는 값이 있지만 다른 사례(None)는 명명된 사례일 뿐입니다. 따라서 Some 사례와 연결된 값에 대한 변수가 Some 있어야 하지만 None 그 자체로 나타나야 합니다. 다음 코드에서 변수 var1 에는 사례와 일치하여 얻은 값이 Some 제공됩니다.

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

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

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}"
| _ -> ()

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

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

변수 패턴

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

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

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 Pattern

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

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

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

OR 패턴

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 이 항목의 뒷부분에 있는 튜플 패턴 섹션에 나와 있지만 여기서는 AND var1var2 패턴을 사용하여 값으로 가져옵니다.

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

튜플 패턴

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

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

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"

와일드카드 패턴

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

형식 주석이 있는 패턴

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

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()

Nameof 패턴

해당 값이 nameof 키워드(keyword) 뒤에 있는 식과 같으면 패턴이 문자열과 일치합니다 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 이름을 사용할 수 있는 항목에 대한 자세한 내용은 운영자를 참조하세요.

참고 항목