다음을 통해 공유


패턴 일치(F#)

패턴은 입력 데이터를 변환하는 규칙입니다. F# 언어 전체에 사용되는 이 패턴은 데이터를 하나 이상의 논리적 구조체와 비교하거나, 데이터를 구성 성분으로 분해하거나, 다양한 방식으로 데이터에서 정보를 추출하는 기능을 수행합니다.

설명

패턴은 match 식 같은 여러 가지 언어 구문에 사용됩니다. 패턴은 let 바인딩, 람다 식 및 try...with 식과 관련된 예외 처리기에서 함수의 인수를 처리하는 데 사용됩니다. 자세한 내용은 일치 식(F#), let 바인딩(F#), 람다 식: fun 키워드(F#)예외: try...with 식(F#)을 참조하십시오.

예를 들어 match 식에서는 pattern이 파이프 기호 뒤에 옵니다.

match expression with

| pattern [ when condition ] -> result-expression

...

각 패턴은 일정한 방식으로 입력을 변환하는 규칙의 역할을 합니다. match 식에서는 각 패턴을 차례로 조사하여 입력 데이터가 패턴에 맞는지 여부를 확인합니다. 일치하는 항목을 만나면 결과 식이 실행됩니다. 일치하는 항목을 찾지 못하면 다음 차례의 패턴 규칙을 테스트합니다. 선택적 요소인 when condition 부분에 대해서는 일치 식(F#)에서 설명합니다.

다음 표에는 지원되는 패턴이 나와 있습니다. 런타임에 표에 나와 있는 순서에 따라 각 패턴에 대해 입력을 테스트합니다. 패턴은 코드에 적혀 있는 대로 처음부터 마지막까지, 각 줄의 패턴에 대해 왼쪽에서 오른쪽으로 되풀이하여 적용됩니다.

이름

설명

예제

상수 패턴

임의의 숫자, 문자 또는 문자열 리터럴, 열거형 상수, 정의된 리터럴 식별자

1.0, "test", 30, Color.Red

식별자 패턴

구별된 공용 구조체, 예외 레이블 또는 활성 패턴 case의 case 값

Some(x)

Failure(msg)

변수 패턴

identifier

a

as 패턴

pattern as identifier

(a, b) as tuple1

OR 패턴

pattern1 | pattern2

([h] | [h; _])

AND 패턴

pattern1 & pattern2

(a, b) & (_, "test")

Cons 패턴

identifier :: list-identifier

h :: t

목록 패턴

[ pattern_1; ... ; pattern_n ]

[ a; b; c ]

배열 패턴

[| pattern_1; ..; pattern_n ]

[| a; b; c |]

범위 패턴

( pattern )

( 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

상수 패턴

상수 패턴은 숫자, 문자, 문자열 리터럴, 열거형 상수(열거형 형식의 이름 포함)입니다. 상수 패턴만 있는 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

식별자 패턴

패턴이 유효한 식별자를 구성하는 문자열인 경우 식별자의 양식은 패턴이 일치하는 방식을 결정합니다. 식별자가 여러 문자로 되어 있고 대문자로 시작하면 컴파일러에서 식별자 패턴과의 일치 여부를 확인하려 시도합니다. 이 패턴의 식별자는 리터럴 특성, 구분된 공용 구조체 케이스, 예외 식별자 또는 활성 패턴 케이스로 표시된 값이 될 수 있습니다. 일치하는 식별자를 찾지 못하면 일치에 실패하고 다음 번 패턴 규칙인 변수 패턴을 입력과 비교합니다.

구별된 공용 구조체 패턴은 간단히 명명된 case일 수도 있고 값을 갖거나 여러 값이 포함된 튜플을 가질 수 있습니다. 값이 있는 경우 해당 값에 대한 식별자를 지정해야 합니다. 튜플의 경우 튜플 패턴에 각 튜플 요소의 식별자 또는 하나 이상의 이름이 지정된 공용 구조체 필드에 대한 필드 이름이 포함된 식별자를 제공해야 합니다. 구체적인 사례는 이 단원의 코드 예제를 참조하십시오.

option 형식은 Some과 None이라는 두 case가 있는 구별된 공용 구조체입니다. 이들 중 한 case(Some)는 값이 있는 case이고, 다른 case(None)는 단순히 이름만 지정된 case입니다. 따라서 Some에는 Some case와 관련된 값의 변수가 있어야 하지만 None은 단독으로 표시되어야 합니다. 다음 코드에서는 Some case와의 일치를 통해 얻은 값이 변수 var1에 부여됩니다.

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

다음 예제에서 구별된 공용 구조체 PersonName에는 이름을 구성할 수 있는 형식을 나타내는 문자열과 문자의 혼합이 포함됩니다. 구별된 공용 구조체의 case는 FirstOnly, LastOnly 및 FirstLast입니다.

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 and width %f" h w
| _ -> ()

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

식별자가 예외인 case는 예외 처리기의 컨텍스트에서 패턴 일치에 사용됩니다. 예외 처리의 패턴 일치에 대한 자세한 내용은 예외: try...with 식(F#)을 참조하십시오.

변수 패턴

변수 패턴은 변수 이름에 일치하는 값을 할당합니다. 이렇게 할당된 값을 -> 기호 오른쪽에 있는 실행 식에 사용할 수 있습니다. 변수 패턴만으로도 임의의 입력에 대한 일치 여부를 확인할 수 있지만 일반적으로 변수 패턴은 다른 패턴 내에 사용됩니다. 변수 패턴을 이와 같이 사용하면 변수로 분해되는 튜플과 배열 같은 더 복잡한 구조체를 만들 수 있습니다.

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

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 절이 추가된 패턴입니다. 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 패턴을 사용하여 var1과 var2를 모두 값으로 얻습니다.

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)

Cons 패턴

cons 패턴은 목록을 헤드와 테일로 분해하는 데 사용됩니다. 헤드는 목록의 첫째 요소이고, 테일은 나머지 요소를 포함하는 목록입니다.

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 "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 패턴과 cons 패턴 사이의 결합 관계를 제어합니다.

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

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

참고 항목

참조

일치 식(F#)

활성 패턴(F#)

기타 리소스

F# 언어 참조