매개 변수 및 인수

이 항목에서는 매개 변수를 정의하고 함수, 메서드 및 속성에 인수를 전달하는 언어 지원에 대해 설명합니다. 참조를 통해 전달하는 방법 및 다양한 수의 인수를 사용할 수 있는 메서드를 정의하고 사용하는 방법에 대한 정보가 포함됩니다.

매개 변수 및 인수

용어 매개 변수 는 제공될 것으로 예상되는 값의 이름을 설명하는 데 사용됩니다. 용어 인수 는 각 매개 변수에 제공된 값에 사용됩니다.

매개 변수는 튜플 또는 커리 형식으로 또는 둘의 일부 조합으로 지정할 수 있습니다. 명시적 매개 변수 이름을 사용하여 인수를 전달할 수 있습니다. 메서드의 매개 변수는 선택 사항으로 지정하고 기본값을 지정할 수 있습니다.

매개 변수 패턴

함수 및 메서드에 제공되는 매개 변수는 일반적으로 공백으로 구분된 패턴입니다. 즉, 일치 식에 설명된 모든 패턴을 함수 또는 멤버의 매개 변수 목록에서 사용할 수 있습니다.

메서드는 일반적으로 인수 전달의 튜플 형식을 사용합니다. 이렇게 하면 튜플 형식이 .NET 메서드에서 인수가 전달되는 방식과 일치하므로 다른 .NET 언어의 관점에서 더 명확한 결과를 얻을 수 있습니다.

큐리된 양식은 바인딩을 사용하여 let 만든 함수와 함께 가장 자주 사용됩니다.

다음 의사 코드는 튜플 및 커리 인수의 예를 보여 줍니다.

// Tuple form.
member this.SomeMethod(param1, param2) = ...
// Curried form.
let function1 param1 param2 = ...

일부 인수가 튜플에 있고 일부는 그렇지 않은 경우 결합된 양식이 가능합니다.

let function2 param1 (param2a, param2b) param3 = ...

다른 패턴은 매개 변수 목록에서도 사용할 수 있지만 매개 변수 패턴이 가능한 모든 입력과 일치하지 않는 경우 런타임에 불완전한 일치 항목이 있을 수 있습니다. 인수 값이 매개 변수 목록에 지정된 패턴과 일치하지 않으면 예외 MatchFailureException 가 생성됩니다. 매개 변수 패턴이 불완전한 일치를 허용하는 경우 컴파일러에서 경고를 발생합니다. 하나 이상의 다른 패턴이 매개 변수 목록에 일반적으로 유용하며 이는 야생카드 패턴입니다. 제공된 인수를 무시하려는 경우 매개 변수 목록에서 wild카드 패턴을 사용합니다. 다음 코드에서는 인수 목록에서 wild카드 패턴을 사용하는 방법을 보여 줍니다.

let makeList _ = [ for i in 1 .. 100 -> i * i ]
// The arguments 100 and 200 are ignored.
let list1 = makeList 100
let list2 = makeList 200

와일드카드 패턴은 다음 코드와 같이 일반적으로 문자열 배열로 제공되는 명령줄 인수에 관심이 없는 경우 프로그램에 대한 기본 진입점과 같이 전달된 인수가 필요하지 않을 때마다 유용할 수 있습니다.

[<EntryPoint>]
let main _ =
    printfn "Entry point!"
    0

인수에 사용되는 다른 패턴은 as 구분된 공용 구조체 및 활성 패턴과 관련된 패턴 및 식별자 패턴입니다. 다음과 같이 단일 사례 구분 공용 구조체 패턴을 사용할 수 있습니다.

type Slice = Slice of int * int * string

let GetSubstring1 (Slice(p0, p1, text)) =
    printfn "Data begins at %d and ends at %d in string %s" p0 p1 text
    text[p0..p1]

let substring = GetSubstring1 (Slice(0, 4, "Et tu, Brute?"))
printfn "Substring: %s" substring

출력은 다음과 같습니다.

Data begins at 0 and ends at 4 in string Et tu, Brute?
Et tu

활성 패턴은 다음 예제와 같이 인수를 원하는 형식으로 변환할 때 매개 변수로 유용할 수 있습니다.

type Point = { x : float; y : float }

let (| Polar |) { x = x; y = y} =
    ( sqrt (x*x + y*y), System.Math.Atan (y/ x) )

let radius (Polar(r, _)) = r
let angle (Polar(_, theta)) = theta

다음 코드 줄에 표시된 것처럼 이 패턴을 사용하여 as 일치하는 값을 로컬 값으로 저장할 수 있습니다.

let GetSubstring2 (Slice(p0, p1, text) as s) = s

가끔 사용되는 또 다른 패턴은 함수의 본문으로 암시적 인수에 패턴 일치를 즉시 수행하는 람다 식을 제공하여 마지막 인수를 명명되지 않은 것으로 남기는 함수입니다. 이 예제는 다음 코드 줄입니다.

let isNil = function [] -> true | _::_ -> false

이 코드는 제네릭 목록을 사용하고 목록이 비어 있으면 반환하는 함수를 정의하고false, 그렇지 않으면 반환 true 합니다. 이러한 기술을 사용하면 코드를 읽기가 더 어려워질 수 있습니다.

경우에 따라 불완전한 일치 항목이 포함된 패턴이 유용합니다. 예를 들어 프로그램의 목록에 세 개의 요소만 있다는 것을 알고 있는 경우 매개 변수 목록에서 다음과 같은 패턴을 사용할 수 있습니다.

let sum [a; b; c;] = a + b + c

불완전한 일치 항목이 있는 패턴의 사용은 빠른 프로토타입 생성 및 기타 임시 용도에 가장 적합합니다. 컴파일러는 이러한 코드에 대한 경고를 실행합니다. 이러한 패턴은 가능한 모든 입력의 일반적인 사례를 다룰 수 없으므로 구성 요소 API에 적합하지 않습니다.

명명된 인수

메서드에 대한 인수는 쉼표로 구분된 인수 목록의 위치로 지정하거나 이름을 제공한 다음 등호와 전달할 값을 제공하여 메서드에 명시적으로 전달할 수 있습니다. 이름을 제공하여 지정한 경우 선언에 사용된 순서와 다른 순서로 표시될 수 있습니다.

명명된 인수를 사용하면 메서드 매개 변수의 순서를 다시 지정하는 등 API의 특정 유형의 변경 내용에 코드를 더 읽기 능하고 더 쉽게 조정할 수 있습니다.

명명된 인수는 -bound 함수, 함수 값 또는 람다 식이 아닌 메서드에 let만 허용됩니다.

다음 코드 예제에서는 명명된 인수를 사용하는 방법을 보여 줍니다.

type SpeedingTicket() =
    member this.GetMPHOver(speed: int, limit: int) = speed - limit

let CalculateFine (ticket : SpeedingTicket) =
    let delta = ticket.GetMPHOver(limit = 55, speed = 70)
    if delta < 20 then 50.0 else 100.0

let ticket1 : SpeedingTicket = SpeedingTicket()
printfn "%f" (CalculateFine ticket1)

클래스 생성자에 대한 호출에서 명명된 인수와 유사한 구문을 사용하여 클래스의 속성 값을 설정할 수 있습니다. 다음 예제에서는 이 구문을 보여줍니다.

 type Account() =
    let mutable balance = 0.0
    let mutable number = 0
    let mutable firstName = ""
    let mutable lastName = ""
    member this.AccountNumber
       with get() = number
       and set(value) = number <- value
    member this.FirstName
       with get() = firstName
       and set(value) = firstName <- value
    member this.LastName
       with get() = lastName
       and set(value) = lastName <- value
    member this.Balance
       with get() = balance
       and set(value) = balance <- value
    member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
    member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount


let account1 = new Account(AccountNumber=8782108,
                           FirstName="Darren", LastName="Parker",
                           Balance=1543.33)

자세한 내용은 생성자(F#)를 참조하세요.

속성 setter를 호출하기 위한 동일한 기술은 모든 개체 반환 메서드(예: 팩터리 메서드)에도 적용됩니다.

type Widget() =
    member val Width = 1 with get,set
    member val Height = 1 with get,set

type WidgetFactory =
    static member MakeNewWidget() =
         new Widget()
    static member AdjustWidget(w: Widget) =
         w
let w = WidgetFactory.MakeNewWidget(Width=10)
w.Width // = 10
w.Height // = 1
WidgetFactory.AdjustWidget(w, Height=10)
w.Height // = 10

이러한 멤버는 임의의 작업을 수행할 수 있으며 구문은 최종 값을 반환하기 전에 속성 setter를 호출하는 짧은 손입니다.

선택적 매개 변수

매개 변수 이름 앞에 물음표를 사용하여 메서드에 대한 선택적 매개 변수를 지정할 수 있습니다. 선택적 매개 변수는 F# 옵션 형식으로 해석되므로 식을 사용하여 matchSomeNone옵션 형식을 쿼리하는 일반적인 방식으로 쿼리할 수 있습니다. 선택적 매개 변수는 바인딩을 사용하여 let 만든 함수가 아닌 멤버에만 허용됩니다.

기존 선택적 값을 메서드에 매개 변수 이름(예: 또는 ?arg=Some(3)?arg=arg.)으로 ?arg=None 전달할 수 있습니다. 선택적 인수를 다른 메서드에 전달하는 메서드를 빌드할 때 유용할 수 있습니다.

선택적 인수의 기본값을 설정하는 함수 defaultArg를 사용할 수도 있습니다. 함수는 defaultArg 선택적 매개 변수를 첫 번째 인수로, 기본값을 두 번째 인수로 사용합니다.

다음 예제에서는 선택적 매개 변수를 사용하는 방법을 보여 줍니다.

type DuplexType =
    | Full
    | Half

type Connection(?rate0 : int, ?duplex0 : DuplexType, ?parity0 : bool) =
    let duplex = defaultArg duplex0 Full
    let parity = defaultArg parity0 false
    let mutable rate = match rate0 with
                        | Some rate1 -> rate1
                        | None -> match duplex with
                                  | Full -> 9600
                                  | Half -> 4800
    do printfn "Baud Rate: %d Duplex: %A Parity: %b" rate duplex parity

let conn1 = Connection(duplex0 = Full)
let conn2 = Connection(duplex0 = Half)
let conn3 = Connection(300, Half, true)
let conn4 = Connection(?duplex0 = None)
let conn5 = Connection(?duplex0 = Some(Full))

let optionalDuplexValue : option<DuplexType> = Some(Half)
let conn6 = Connection(?duplex0 = optionalDuplexValue)

출력은 다음과 같습니다.

Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
Baud Rate: 300 Duplex: Half Parity: true
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false

C# 및 Visual Basic interop의 목적을 위해 F#의 특성을 [<Optional; DefaultParameterValue<(...)>] 사용하면 호출자가 인수를 선택 사항으로 볼 수 있습니다. 이는 C#에서와 같이 인수를 선택 사항으로 정의하는 것과 MyMethod(int i = 3)같습니다.

open System
open System.Runtime.InteropServices
type C =
    static member Foo([<Optional; DefaultParameterValue("Hello world")>] message) =
        printfn $"{message}"

새 개체를 기본 매개 변수 값으로 지정할 수도 있습니다. 예를 들어 멤버는 Foo 대신 선택적 CancellationToken 입력을 가질 수 있습니다.

open System.Threading
open System.Runtime.InteropServices
type C =
    static member Foo([<Optional; DefaultParameterValue(CancellationToken())>] ct: CancellationToken) =
        printfn $"{ct}"

인수 DefaultParameterValue 로 지정된 값은 매개 변수의 형식과 일치해야 합니다. 예를 들어 다음은 허용되지 않습니다.

type C =
    static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()

이 경우 컴파일러는 경고를 생성하고 두 특성을 모두 무시합니다. 그렇지 않으면 컴파일러가 잘못된 형식을 유추하기 때문에 기본값 null 은 형식 주석을 추가해야 합니다. [<Optional; DefaultParameterValue(null:obj)>] o:obj

참조로 전달

참조로 F# 값을 전달하려면 관리되는 포인터 형식인 byrefs가 포함됩니다. 사용할 형식에 대한 지침은 다음과 같습니다.

  • 포인터를 읽어야 하는 경우에만 사용합니다 inref<'T> .
  • 포인터에 쓰기만 해야 하는 경우 사용합니다 outref<'T> .
  • 포인터에서 읽고 포인터에 쓸 필요가 있는 경우 사용합니다 byref<'T> .
let example1 (x: inref<int>) = printfn $"It's %d{x}"

let example2 (x: outref<int>) = x <- x + 1

let example3 (x: byref<int>) =
    printfn $"It's %d{x}"
    x <- x + 1

let test () =
    // No need to make it mutable, since it's read-only
    let x = 1
    example1 &x

    // Needs to be mutable, since we write to it
    let mutable y = 2
    example2 &y
    example3 &y // Now 'y' is 3

매개 변수는 포인터이고 값은 변경 가능하므로 함수를 실행한 후에는 값에 대한 변경 내용이 유지됩니다.

튜플을 반환 값으로 사용하여 모든 out 매개 변수를 .NET 라이브러리 메서드에 저장할 수 있습니다. 또는 매개 변수를 out 매개 변수로 byref 처리할 수 있습니다. 다음 코드 예제에서는 두 가지 방법을 모두 보여 줍니다.

// TryParse has a second parameter that is an out parameter
// of type System.DateTime.
let (b, dt) = System.DateTime.TryParse("12-20-04 12:21:00")

printfn "%b %A" b dt

// The same call, using an address of operator.
let mutable dt2 = System.DateTime.Now
let b2 = System.DateTime.TryParse("12-20-04 12:21:00", &dt2)

printfn "%b %A" b2 dt2

매개 변수 배열

경우에 따라 유형이 다른 형식의 임의의 개수의 매개 변수를 사용하는 함수를 정의해야 합니다. 사용할 수 있는 모든 형식을 설명하기 위해 가능한 모든 오버로드된 메서드를 만드는 것은 실용적이지 않습니다. .NET 구현은 매개 변수 배열 기능을 통해 이러한 메서드를 지원합니다. 해당 서명에서 매개 변수 배열을 사용하는 메서드는 임의의 개수의 매개 변수와 함께 제공할 수 있습니다. 매개 변수는 배열에 배치됩니다. 배열 요소의 형식은 함수에 전달할 수 있는 매개 변수 형식을 결정합니다. 매개 변수 배열 System.Object 을 요소 형식으로 정의하는 경우 클라이언트 코드는 모든 형식의 값을 전달할 수 있습니다.

F#에서 매개 변수 배열은 메서드에서만 정의할 수 있습니다. 모듈에 정의된 독립 실행형 함수 또는 함수에서는 사용할 수 없습니다.

특성을 사용하여 매개 변수 배열을 ParamArray 정의합니다. 특성은 ParamArray 마지막 매개 변수에만 적용할 수 있습니다.

다음 코드에서는 매개 변수 배열을 사용하는 .NET 메서드 호출과 매개 변수 배열을 사용하는 메서드가 있는 F#의 형식 정의를 모두 보여 줍니다.

open System

type X() =
    member this.F([<ParamArray>] args: Object[]) =
        for arg in args do
            printfn "%A" arg

[<EntryPoint>]
let main _ =
    // call a .NET method that takes a parameter array, passing values of various types
    Console.WriteLine("a {0} {1} {2} {3} {4}", 1, 10.0, "Hello world", 1u, true)

    let xobj = new X()
    // call an F# method that takes a parameter array, passing values of various types
    xobj.F("a", 1, 10.0, "Hello world", 1u, true)
    0

프로젝트에서 실행하는 경우 이전 코드의 출력은 다음과 같습니다.

a 1 10 Hello world 1 True
"a"
1
10.0
"Hello world"
1u
true

참고 항목