インターフェイス (F#)
インターフェイスでは、他のクラスが実装する関連メンバーのセットを指定します。
// Interface declaration:
[ attributes ]
type interface-name =
[ interface ]
[ inherit base-interface-name ...]
abstract member1 : [ argument-types1 -> ] return-type1
abstract member2 : [ argument-types2 -> ] return-type2
...
[ end ]
// Implementing, inside a class type definition:
interface interface-name with
member self-identifier.member1 argument-list = method-body1
member self-identifier.member2 argument-list = method-body2
// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
{ new interface-name with
member self-identifier.member1 argument-list = method-body1
member self-identifier.member2 argument-list = method-body2
[ base-interface-definitions ]
}
member-list
解説
インターフェイス宣言はクラス宣言に似ていますが、メンバーが実装されません。その代わり、abstract キーワードが指定されるため、すべてのメンバーが抽象メンバーになります。抽象メソッドではメソッド本体を記述しません。ただし、default キーワードを使用して、メンバーのメソッドとしての定義を個別に追加することにより、既定の実装を指定できます。これは、他の .NET 言語において基本クラスの仮想メソッドを作成することに相当します。このような仮想メソッドは、インターフェイスを実装するクラスでオーバーライドできます。
インターフェイスを実装する方法には、オブジェクト式を使用する方法とクラス型を使用する方法の 2 つがあります。どちらの場合でも、クラス型またはオブジェクト式を使用して、インターフェイスの抽象メソッドのメソッド本体を指定します。実装は、インターフェイスを実装する各型に対して固有です。このため、インターフェイス メソッドの型が異なる場合は、それらのメソッドが互いに異なるメソッドになります。
定義の開始と終了を示す interface キーワードと end キーワードは、軽量構文を使用する場合には省略可能です。これらのキーワードを使用しない場合、コンパイラは、使用されている構成要素を分析することにより、型がクラス型とインターフェイス型のどちらであるかを推論しようとします。メンバーが定義されている場合、または他のクラスの構文が使用されている場合は、クラス型として解釈されます。
.NET のコーディング スタイルでは、インターフェイスはすべて、大文字の I で始めます。
クラス型を使用したインターフェイスの実装
クラス型の 1 つ以上のインターフェイスを実装するには、次のコードに示すように、interface キーワード、インターフェイス名、with キーワード、インターフェイス メンバーの定義の順に記述します。
type IPrintable =
abstract member Print : unit -> unit
type SomeClass1(x: int, y: float) =
interface IPrintable with
member this.Print() = printfn "%d %f" x y
インターフェイスの実装は継承されるので、派生クラスでインターフェイスを再度実装する必要はありません。
インターフェイス メソッドの呼び出し
インターフェイス メソッドは、インターフェイスを介してのみ呼び出すことができます。インターフェイスを実装する型のオブジェクトを介して呼び出すことはできません。したがって、インターフェイス メソッドを呼び出すために、:> 演算子または upcast 演算子を使用して、インターフェイス型にアップキャストすることが必要な場合があります。
SomeClass 型のオブジェクトでインターフェイス メソッドを呼び出すには、次のコードに示すように、オブジェクトをインターフェイス型にアップキャストする必要があります。
let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()
もう 1 つの方法は、次の例のように、インターフェイス メソッドをアップキャストして呼び出すオブジェクトでメソッドを宣言する方法です。
type SomeClass2(x: int, y: float) =
member this.Print() = (this :> IPrintable).Print()
interface IPrintable with
member this.Print() = printfn "%d %f" x y
let x2 = new SomeClass2(1, 2.0)
x2.Print()
オブジェクト式を使用したインターフェイスの実装
オブジェクト式を使用すると、簡単にインターフェイスを実装できます。この方法は、名前付きの型を作成する必要がない場合や、インターフェイス メソッドをサポートするオブジェクトが必要なだけの場合に、メソッドを追加する必要がないため、便利です。次のコードに、オブジェクト式の例を示します。
let makePrintable(x: int, y: float) =
{ new IPrintable with
member this.Print() = printfn "%d %f" x y }
let x3 = makePrintable(1, 2.0)
x3.Print()
インターフェイスの継承
インターフェイスは、1 つ以上の基本インターフェイスから継承できます。
type Interface1 =
abstract member Method1 : int -> int
type Interface2 =
abstract member Method2 : int -> int
type Interface3 =
inherit Interface1
inherit Interface2
abstract member Method3 : int -> int
type MyClass() =
interface Interface3 with
member this.Method1(n) = 2 * n
member this.Method2(n) = n + 100
member this.Method3(n) = n / 10