수색…
단순한 활성 패턴
활성 패턴은 데이터가 들어갈 수있는 명명 된 카테고리를 지정할 수있는 특별한 유형의 패턴 일치 유형이며 match
문에서 해당 범주를 사용합니다.
숫자를 양수, 음수 또는 0으로 분류하는 활성 패턴을 정의하려면 다음을 수행하십시오.
let (|Positive|Negative|Zero|) num =
if num > 0 then Positive
elif num < 0 then Negative
else Zero
다음 패턴 일치 식에서 사용할 수 있습니다.
let Sign value =
match value with
| Positive -> printf "%d is positive" value
| Negative -> printf "%d is negative" value
| Zero -> printf "The value is zero"
Sign -19 // -19 is negative
Sign 2 // 2 is positive
Sign 0 // The value is zero
매개 변수가있는 활성 패턴
활성 패턴은 단순한 기능입니다.
함수와 마찬가지로 추가 매개 변수를 정의 할 수 있습니다.
let (|HasExtension|_|) expected (uri : string) =
let result = uri.EndsWith (expected, StringComparison.CurrentCultureIgnoreCase)
match result with
| true -> Some true
| _ -> None
이 방법으로 일치하는 패턴에서 사용할 수 있습니다.
let isXMLFile uri =
match uri with
| HasExtension ".xml" _ -> true
| _ -> false
활성 패턴은 함수 인수의 유효성을 검사하고 변환하는 데 사용할 수 있습니다.
F#
에서 액티브 패턴의 흥미롭지 만 사용되지 않는 사용법은 함수 인수를 검증하고 변환하는 데 사용할 수 있다는 것입니다.
인수 검증을 수행하는 고전적인 방법을 고려하십시오.
// val f : string option -> string option -> string
let f v u =
let v = defaultArg v "Hello"
let u = defaultArg u "There"
v + " " + u
// val g : 'T -> 'T (requires 'T null)
let g v =
match v with
| null -> raise (System.NullReferenceException ())
| _ -> v.ToString ()
일반적으로 메소드에 코드를 추가하여 인수가 올바른지 확인합니다. F#
에서 액티브 패턴을 사용하여 이것을 일반화하고 인수 선언에서 인 텐트를 선언 할 수 있습니다.
다음 코드는 위의 코드와 동일합니다.
let inline (|DefaultArg|) dv ov = defaultArg ov dv
let inline (|NotNull|) v =
match v with
| null -> raise (System.NullReferenceException ())
| _ -> v
// val f : string option -> string option -> string
let f (DefaultArg "Hello" v) (DefaultArg "There" u) = v + " " + u
// val g : 'T -> string (requires 'T null)
let g (NotNull v) = v.ToString ()
함수 f
와 g
의 사용자에게는 두 가지 버전간에 차이가 없습니다.
printfn "%A" <| f (Some "Test") None // Prints "Test There"
printfn "%A" <| g "Test" // Prints "Test"
printfn "%A" <| g null // Will throw
Active Patterns가 성능 오버 헤드를 추가하는 경우 문제가 발생할 수 있습니다. 이 경우에 ILSpy
를 사용하여 f
와 g
를 디 컴파일하여 봅시다.
public static string f(FSharpOption<string> _arg2, FSharpOption<string> _arg1)
{
return Operators.DefaultArg<string>(_arg2, "Hello") + " " + Operators.DefaultArg<string>(_arg1, "There");
}
public static string g<a>(a _arg1) where a : class
{
if (_arg1 != null)
{
a a = _arg1;
return a.ToString();
}
throw new NullReferenceException();
}
inline
덕택에 액티브 패턴은 기존의 인수 검증 방법과 비교하여 추가 오버 헤드를 추가하지 않습니다.
.NET API 래퍼로서의 활성 패턴
Active Patterns는 좀더 자연스러운, 특히 함수 반환 값 이상을 반환하는 출력 매개 변수를 사용하는 .NET API의 느낌을 호출하는 데 사용할 수 있습니다.
예를 들어, 일반적으로 System.Int32.TryParse
메서드를 다음과 같이 호출합니다.
let couldParse, parsedInt = System.Int32.TryParse("1")
if couldParse then printfn "Successfully parsed int: %i" parsedInt
else printfn "Could not parse int"
패턴 매칭을 사용하여 조금 향상시킬 수 있습니다.
match System.Int32.TryParse("1") with
| (true, parsedInt) -> printfn "Successfully parsed int: %i" parsedInt
| (false, _) -> printfn "Could not parse int"
그러나 System.Int32.TryParse
함수를 래핑하는 다음과 같은 활성 패턴을 정의 할 수도 있습니다.
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| (true, parsedInt) -> Some parsedInt
| _ -> None
이제 다음을 수행 할 수 있습니다.
match "1" with
| Int parsedInt -> printfn "Successfully parsed int: %i" parsedInt
| _ -> printfn "Could not parse int"
액티브 패턴으로 싸이기위한 또 다른 좋은 방법은 정규 표현식 API입니다.
let (|MatchRegex|_|) pattern input =
let m = System.Text.RegularExpressions.Regex.Match(input, pattern)
if m.Success then Some m.Groups.[1].Value
else None
match "bad" with
| MatchRegex "(good|great)" mood ->
printfn "Wow, it's a %s day!" mood
| MatchRegex "(bad|terrible)" mood ->
printfn "Unfortunately, it's a %s day." mood
| _ ->
printfn "Just a normal day"
전체 및 부분 활성 패턴
사용 패턴이 다소 다른 두 가지 유형의 활성 패턴 (전체 및 부분)이 있습니다.
완전한 활성 패턴은 "결과가 홀수 또는 홀수입니까?"와 같이 모든 결과를 열거 할 수있을 때 사용할 수 있습니다.
let (|Odd|Even|) number =
if number % 2 = 0
then Even
else Odd
활성 패턴 정의에는 가능한 경우와 그 외에는 모두 나열되지 않으며 본문은 나열된 사례 중 하나를 반환합니다. 일치 식에 사용하면 다음과 같이 완전 일치합니다.
let n = 13
match n with
| Odd -> printf "%i is odd" n
| Even -> printf "%i is even" n
입력 공간을 완전히 커버하는 알려진 카테고리로 나누고 싶을 때 유용합니다.
반면 부분 활성 패턴을 사용하면 option
을 반환하여 가능한 일부 결과를 명시 적으로 무시할 수 option
. 그들의 정의는 타의 추종을 불허하는 경우에 _
의 특별한 경우를 사용합니다.
let (|Integer|_|) str =
match Int32.TryParse(str) with
| (true, i) -> Some i
| _ -> None
이렇게하면 우리의 파싱 기능으로는 어떤 경우를 처리 할 수없는 경우에도 일치시킬 수 있습니다.
let s = "13"
match s with
| Integer i -> "%i was successfully parsed!" i
| _ -> "%s is not an int" s
부분 활성 패턴은 다른 옵션을 무시하면서 입력이 입력 공간의 특정 범주에 속하는지 여부에 관계없이 테스트 형식으로 사용할 수 있습니다.