次の方法で共有


メソッド

メソッドは、型に関連付けられている関数です。 オブジェクト指向プログラミングでは、メソッドを使用して、オブジェクトと型の機能と動作を公開および実装します。

構文

// 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 method-name : type-signature

// Virtual method declaration and default implementation.
[ attributes ]
abstract member method-name : type-signature
[ attributes ]
default self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Override of inherited virtual method.
[ attributes ]
override self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Optional and DefaultParameterValue attributes on input parameters
[ attributes ]
[ modifier ] member [inline] self-identifier.method-name ([<Optional; DefaultParameterValue( default-value )>] input) [ : return-type ]

注釈

前の構文では、さまざまな形式のメソッド宣言と定義を確認できます。 長いメソッド本体では、改行は等号 (=) に従い、メソッド本体全体がインデントされます。

属性は、任意のメソッド宣言に適用できます。 メソッド定義の構文の前にあり、通常は別の行に一覧表示されます。 詳細については、「属性の」を参照してください。

メソッドは inlineマークできます。 inlineの詳細については、「インライン関数」を参照してください。

インライン以外のメソッドは、型内で再帰的に使用できます。 rec キーワードを明示的に使用する必要はありません。

インスタンス メソッド

インスタンス メソッドは、 member キーワードと 自己識別子を使用して宣言され、その後にピリオド (.) とメソッド名とパラメーターが続きます。 letバインドの場合と同様に、パラメーター リストはパターンにすることができます。 通常、メソッド パラメーターはタプル形式でかっこで囲みます。これは、メソッドが他の .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 つ存在する クラスは抽象クラスです。つまり、そのクラスのインスタンスを作成することはできません。 抽象クラスの詳細については、「 抽象クラス」を参照してください。

抽象メソッド宣言には、メソッド本体は含まれません。 代わりに、メソッドの名前の後にコロン (:)とメソッドの型シグネチャが続きます。 メソッドの型シグネチャは、パラメーター名を除き、Visual Studio Code エディターでメソッド名の上にマウス ポインターを置いたときに IntelliSense で表示されるシグネチャと同じです。 対話形式で作業している場合は、インタープリター (fsi.exe) によっても型署名が表示されます。 メソッドの型シグネチャは、パラメーターの型を一覧表示し、その後に戻り値の型を適切な区切り記号で列挙することによって形成されます。 カリー化されたパラメーターは -> で区切られ、タプル パラメーターは *で区切られます。 戻り値は、常に -> シンボルによって引数から分離されます。 かっこを使用すると、関数型がパラメーターの場合など、複雑なパラメーターをグループ化したり、タプルが 2 つのパラメーターとしてではなく単一のパラメーターとして扱われるタイミングを示したりできます。

このトピックの構文ブロックに示すように、クラスに定義を追加し、 default キーワードを使用して抽象メソッドに既定の定義を指定することもできます。 同じクラスの定義を持つ抽象メソッドは、他の .NET Framework 言語の仮想メソッドと同等です。 定義が存在するかどうかに関係なく、 abstract キーワードは、クラスの仮想関数テーブルに新しいディスパッチ スロットを作成します。

基底クラスが抽象メソッドを実装しているかどうかに関係なく、派生クラスは抽象メソッドの実装を提供できます。 派生クラスに抽象メソッドを実装するには、 override キーワードまたは default キーワードを使用する以外は、派生クラスで同じ名前とシグネチャを持つメソッドを定義し、メソッド本体を指定します。 キーワード overridedefault はまったく同じことを意味します。 新しいメソッドが基底クラスの実装をオーバーライドする場合は 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# では、通常、オーバーロードされたメソッドの代わりに省略可能な引数が使用されます。 ただし、引数がカリー化された形式ではなくタプル形式である場合、オーバーロードされたメソッドは言語で許可されます。 次の例では、その例を示します。

type MyType(dataIn: int) =
    let data = dataIn
    member this.DoSomething(a: int) = a + data
    member this.DoSomething(a: string) = sprintf "Hello world, %s!" a

let m = MyType(10)
printfn "With int: %d" (m.DoSomething(2)) // With int: 12
printfn "With string: %s" (m.DoSomething("Bill")) // With string: Hello world, Bill!

省略可能な引数

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

こちらも参照ください