F# における interface 宣言と実装、そしてオブジェクト式
C#には、インタフェースを宣言するためのキーワード interface が用意されていますが、 F# でのインタフェース宣言は( クラス宣言と同じく)キーワード type を用います。
C# の宣言例
public interface IGreeting { void Say(); }
F# の宣言例
type IGreeting = abstract Say: unit -> unit
これらはどちらも宣言内容は同じになります。F# のインタフェース宣言ではメソッドに abstract 指定が必須になります。またアクセス修飾子(Access Modifiers)を省略するとF#では public に設定されます。
ちなみに上記の F# コードにおける unit
型とは C# における void と同様に「値を何も返さない」ことを表しており、F# コード中では () と記述します。また unit
型は「引数を何も受け取らない」ことも表すので、引数のない関数・メソッドあるいは引数のないコンストラクタの記述にも使われます。
インタフェースの実装例
上記のF# コードのインタフェース IGreeting の宣言に続けて以下のコードで実装を試みます。
type MorningGreeting() = interface IGreeting with override __.Say() = printfn "Good morning !" type EveningGreeting() = interface IGreeting with override __.Say() = printfn "Good evening !" let morning1 = new MorningGreeting() let evening1 = new EveningGreeting() // 実装したメソッドを呼び出すには明示的なキャストが必要(方法その1) (morning1 :> IGreeting).Say() (evening1 :> IGreeting).Say()
インタフェース IGreeting のメソッドを具体的に実装した MorningGreeting クラスおよび EveningGreeting クラスを新規に宣言し、メソッド Say() を呼び出しています。
実行結果
Good morning !
Good evening !
キャストのやり方の別解
// 実装したメソッドを呼び出すには明示的なキャストが必要(方法その2) let morning2 = new MorningGreeting() :> IGreeting let evening2 = new EveningGreeting() :> IGreeting morning2.Say() evening2.Say()
F# ではこのようにインタフェースを実装したクラスのメソッドを呼び出すために、インタフェース型(この例では IGreeting )への明示的なキャストが必要になります。
このコード内の :>
記号はキャスト演算子であり、安全に型変換できるか否かはコンパイラがチェックしてくれます。
オブジェクト式の利用
F# には、インタフェース(あるいは抽象クラス)を実装したクラスのインスタンスをクラス宣言なしで生成する「オブジェクト式(Object Expressions)」と呼ばれる文法があります。 C# における匿名型(Anonymous Types)の文法に似ています。
以下は、インタフェース IGreeting のメソッドの実装をその場で定義して、クラスインスタンスを new 演算子で生成。そのメソッドを呼び出すコードです。前出のコードと違って IGreeting へのキャストは不要になりました。
let morning3 = { new IGreeting with override __.Say() = printfn "Good morning, Object Expression !!!" } let evening3 = { new IGreeting with override __.Say() = printfn "Good evening, Object Expression !!!" } // オブジェクト式を使ったためキャストは不要になった morning3.Say() evening3.Say()
実行結果
Good morning, Object Expression !!!
Good evening, Object Expression !!!