메서드(F#)
메서드는 형식과 관련된 함수입니다.개체 지향 프로그래밍에서 메서드는 개체 및 형식의 기능과 동작을 노출하고 구현하는 데 사용됩니다.
// Instance method definition.
[ attributes ]
member [inline] self-identifier.method-name parameter-list [ : return-type ]=
method-body
// Static method definition.
[ attributes ]
static member [inline] method-name parameter-list [ : return-type ]=
method-body
// Abstract method declaration or virtual dispatch slot.
[ attributes ]
abstract member self-identifier.method-name : type-signature
// Virtual method declaration and default implementation.
[ attributes ]
abstract member [inline] self-identifier.method-name : type-signature
[ attributes ]
default member [inline] self-identifier.method-name parameter-list[ : return-type ] =
method-body
// Override of inherited virtual method.
[ attributes ]
override member [inline] self-identifier.method-name parameter-list [ : return-type ]=
method-body
설명
위 구문에는 여러 가지 형태의 메서드 선언과 정의가 나와 있습니다.메서드 본문이 긴 경우에는 등호(=) 뒤에 줄 바꿈을 추가하고 전체 메서드 본문을 들여씁니다.
임의의 메서드 선언에 특성을 적용할 수 있습니다.특성은 메서드 정의 구문 앞에 오며 일반적으로 별도의 줄을 사용하여 작성합니다.자세한 내용은 특성(F#)을 참조하십시오.
메서드를 inline으로 표시할 수 있습니다.inline에 대한 자세한 내용은 인라인 함수(F#)를 참조하십시오.
비인라인 메서드는 형식 내에서 재귀적으로 사용할 수 있으며 rec 키워드를 명시적으로 사용할 필요는 없습니다.
인스턴스 메서드
인스턴스 메서드에서는 member 키워드 및 self-identifier 뒤에 마침표(.)와 메서드 이름, 매개 변수를 차례로 선언합니다.let 바인딩의 경우와 마찬가지로 parameter-list는 패턴이 될 수 있습니다.일반적으로 메서드 매개 변수를 괄호로 묶어 튜플 형식으로 표시하는 경우가 많습니다. 다른 .NET Framework 언어에서 만든 메서드를 F#에서 표시할 때는 이 방법이 사용됩니다.그 밖에 매개 변수를 공백으로 구분하는 변환 형식도 자주 사용되며 기타 패턴도 지원됩니다.
다음 예제에서는 비추상 인스턴스 메서드를 정의하고 사용하는 방법을 보여 줍니다.
type SomeType(factor0: int) =
let factor = factor0
member this.SomeMethod(a, b, c) =
(a + b + c) * factor
member this.SomeOtherMethod(a, b, c) =
this.SomeMethod(a, b, c) * factor
인스턴스 메서드 내에서는 let 바인딩을 사용하여 정의한 필드에 액세스하는 데 자체 식별자를 사용하지 말아야 합니다.자체 식별자는 다른 멤버와 속성에 액세스할 때 사용해야 합니다.
정적 메서드
인스턴스 없이 메서드를 호출할 수 있고 메서드가 개체 인스턴스에 연결되지 않음을 나타내는 데는 static 키워드가 사용됩니다.이를 제외한 메서드는 인스턴스 메서드입니다.
다음 단원의 예제에서는 let 키워드를 사용하여 선언한 필드, member 키워드를 사용하여 선언한 속성 멤버 및 static 키워드를 사용하여 선언한 정적 메서드를 보여 줍니다.
다음 예제에서는 정적 메서드를 정의하고 사용하는 방법을 보여 줍니다.이 메서드 정의는 앞 단원의 SomeType 클래스에 속한 것으로 가정합니다.
static member SomeStaticMethod(a, b, c) =
(a + b + c)
static member SomeOtherStaticMethod(a, b, c) =
SomeType.SomeStaticMethod(a, b, c) * 100
추상 및 가상 메서드
키워드 abstract는 메서드에 가상 디스패치 슬롯이 있고 클래스에는 메서드의 정의가 없을 수 있음을 의미합니다.가상 디스패치 슬롯은 런타임에 개체 지향 형식의 가상 함수 호출을 조회하는 데 사용되는 함수로 이루어져 있고 내부적으로 유지 관리되는 테이블의 항목입니다.가상 디스패치 메커니즘은 개체 지향 프로그래밍의 중요한 기능 중 하나인 다형성을 구현하는 메커니즘입니다.정의되지 않은 추상 메서드를 적어도 하나 이상 가지고 있는 클래스가 추상 클래스입니다. 이는 해당 클래스에 대해 인스턴스를 만들 수 없다는 의미입니다.추상 클래스에 대한 자세한 내용은 추상 클래스(F#)를 참조하십시오.
추상 메서드 선언에는 메서드 본문이 포함되지 않습니다.대신 메서드의 이름 뒤에 콜론(:)을 추가하고 메서드에 대한 형식 시그니처를 입력합니다.메서드의 형식 시그니처는 매개 변수 이름이 없다는 점을 제외하고는 Visual Studio 코드 편집기에서 메서드 이름 위로 커서를 가져갔을 때 IntelliSense를 통해 표시되는 것과 같습니다.형식 시그니처는 대화형으로 작업할 때 해석기(fsi.exe)를 통해서도 표시됩니다.메서드의 형식 시그니처는 매개 변수 형식 뒤에 반환 형식을 추가하고 적절한 구분 기호로 각 항목을 구분한 목록 형태로 작성합니다.변환 매개 변수를 구분하는 데는 -> 기호를 사용하고, 튜플 매개 변수를 구분하는 데는 * 기호를 사용합니다.반환 값과 인수를 구분하는 데는 항상 -> 기호를 사용합니다.함수 형식이 매개 변수인 경우와 같이 복잡한 매개 변수를 그룹으로 묶으려는 경우나 튜플을 두 개의 매개 변수가 아닌 단일 매개 변수로 취급하려는 경우 등에 괄호를 사용할 수 있습니다.
이 항목의 구문 설명 부분에 나와 있는 것처럼 클래스에 정의를 추가하고 default 키워드를 사용하여 추상 메서드에 대한 기본 정의를 제공할 수도 있습니다.동일한 클래스에 정의가 포함되어 있는 추상 메서드는 다른 .NET Framework 언어의 가상 메서드에 해당합니다.정의가 있는지 여부와 상관없이 abstract 키워드를 사용하면 클래스의 가상 함수 테이블에 새 디스패치 슬롯을 만들 수 있습니다.
기본 클래스에서 추상 메서드를 구현하는지 여부와 상관없이 파생 클래스를 통해 추상 메서드에 대한 구현을 제공할 수 있습니다.파생 클래스에서 추상 메서드를 구현하려면 override 또는 default 키워드를 사용하지 않은 채 파생 클래스에서 이름과 시그니처가 같은 메서드를 정의하고 메서드 본문을 제공하면 됩니다.override 및 default 키워드는 쓰임새만 다를 뿐 의미는 동일합니다.새 메서드에서 기본 클래스 구현을 재정의하는 경우에는 override를 사용하고, 원래 추상 선언과 같은 클래스에 구현을 만드는 경우에는 default를 사용합니다.기본 클래스에 추상으로 선언되어 있는 메서드를 구현하는 메서드에 대해서는 abstract 키워드를 사용하지 말아야 합니다.
다음 예제에서는 .NET Framework 가상 메서드에 상응하는 기본 구현이 있는 Rotate 추상 메서드를 보여 줍니다.
type Ellipse(a0 : float, b0 : float, theta0 : float) =
let mutable axis1 = a0
let mutable axis2 = b0
let mutable rotAngle = theta0
abstract member Rotate: float -> unit
default this.Rotate(delta : float) = rotAngle <- rotAngle + delta
다음 예제에서는 기본 클래스 메서드를 재정의하는 파생 클래스를 보여 줍니다.이 경우 재정의 결과로 동작이 변경되어 메서드가 아무런 작업도 수행하지 않습니다.
type Circle(radius : float) =
inherit Ellipse(radius, radius, 0.0)
// Circles are invariant to rotation, so do nothing.
override this.Rotate(_) = ()
오버로드된 메서드
오버로드된 메서드는 해당 형식에 대해 이름이 동일하지만 인수가 다른 메서드입니다.F#에서는 오버로드된 메서드 대신 선택적 인수를 사용하는 것이 일반적입니다.그러나 변환 형식이 아니라 튜플 형식에서 인수를 사용하는 경우 F#에도 오버로드된 메서드가 허용됩니다.
예제: 속성과 메서드
다음 예제에는 필드, 전용 함수, 속성 및 정적 메서드의 예를 포함하는 형식이 나와 있습니다.
type RectangleXY(x1 : float, y1: float, x2: float, y2: float) =
// Field definitions.
let height = y2 - y1
let width = x2 - x1
let area = height * width
// Private functions.
static let maxFloat (x: float) (y: float) =
if x >= y then x else y
static let minFloat (x: float) (y: float) =
if x <= y then x else y
// Properties.
// Here, "this" is used as the self identifier,
// but it can be any identifier.
member this.X1 = x1
member this.Y1 = y1
member this.X2 = x2
member this.Y2 = y2
// A static method.
static member intersection(rect1 : RectangleXY, rect2 : RectangleXY) =
let x1 = maxFloat rect1.X1 rect2.X1
let y1 = maxFloat rect1.Y1 rect2.Y1
let x2 = minFloat rect1.X2 rect2.X2
let y2 = minFloat rect1.Y2 rect2.Y2
let result : RectangleXY option =
if ( x2 > x1 && y2 > y1) then
Some (RectangleXY(x1, y1, x2, y2))
else
None
result
// Test code.
let testIntersection =
let r1 = RectangleXY(10.0, 10.0, 20.0, 20.0)
let r2 = RectangleXY(15.0, 15.0, 25.0, 25.0)
let r3 : RectangleXY option = RectangleXY.intersection(r1, r2)
match r3 with
| Some(r3) -> printfn "Intersection rectangle: %f %f %f %f" r3.X1 r3.Y1 r3.X2 r3.Y2
| None -> printfn "No intersection found."
testIntersection