メソッド (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 キーワードは、メソッドに仮想ディスパッチ スロットがあり、クラス内には定義がない可能性があることを示します。仮想ディスパッチ スロットは、内部的に管理される関数のテーブル内のエントリであり、実行時にオブジェクト指向型で仮想関数呼び出しを検索するために使用されます。仮想ディスパッチ機構は、オブジェクト指向プログラミングの重要な特徴であるポリモーフィズムを実装する機構です。定義のない抽象メソッドを少なくとも 1 つ含むクラスは、抽象クラスです。つまり、このクラスのインスタンスを作成することはできません。抽象クラスの詳細については、「抽象クラス (F#)」を参照してください。
抽象メソッドの宣言には、メソッド本体は含まれません。ただし、メソッドの名前の後ろに、コロン (:) とメソッドの型シグネチャが続きます。メソッドの型シグネチャは、パラメーター名がないことを除き、Visual Studio コード エディターでメソッド名の上にマウス ポインターを置いたときに IntelliSense によって表示されるものと同じです。また、型シグネチャは、対話形式で作業しているときに、インタープリター fsi.exe によって表示されます。メソッドの型シグネチャは、パラメーターの型と、それに続く戻り値の型を、適切な区切り記号で一覧することにより形成されます。カリー化パラメーターは -> によって区切られ、タプル パラメーターは * によって区切られます。戻り値と引数は常に、-> 記号によって区切られます。かっこを使用して、複雑なパラメーターをグループ化したり (関数型がパラメーターの場合など)、タプルを 2 つのパラメーターではなく単一のパラメーターとして扱うことを示したりすることができます。
また、抽象メソッドに既定の定義を与えることもできます。それには、このトピックの構文ブロックに示すように、クラスに定義を追加し、default キーワードを使用します。同じクラス内に定義を持つ抽象メソッドは、他の .NET Framework 言語の仮想メソッドと等価です。定義が存在するかどうかに関係なく、abstract キーワードにより、クラスの仮想関数テーブル内に新しいディスパッチ スロットが作成されます。
基本クラスが抽象メソッドを実装するかどうかに関係なく、派生クラスで抽象メソッドの定義を提供できます。派生クラスで抽象メソッドを実装するには、同じ名前とシグネチャを持つメソッドを派生クラスで定義し (ただし、override キーワードまたは default キーワードを使用)、メソッド本体を提供します。override キーワードと default キーワードは厳密に同じ意味です。新しいメソッドが基本クラスの実装をオーバーライドする場合は、override を使用します。元の抽象宣言と同じクラス内で実装を作成する場合は、default を使用します。基本クラスで抽象と宣言されたメソッドを実装するメソッドでは、abstract キーワードを使用しないでください。
既定の実装を持つ Rotate 抽象メソッドの例を次に示します。この抽象メソッドは、.NET Framework の仮想メソッドと等価です。
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