クラスキャストの概要
F#のクラス(または構造体)は、オブジェクト階層内の型間で相互に変換できます。これはオブジェクト指向プログラミングにおいて重要なポリモーフィズムを実現するために必須といっても過言ではない機能です。キャストには アップキャスト と ダウンキャスト という2種類の方法があります。アップキャストとは、「派生クラスから基底クラスにキャスト」することを指します。また、ダウンキャストは「基底クラスから派生クラスにキャスト」することを指します。
アップキャストは、基底クラスが派生クラスの継承階層内にある限り、確実に機能します。しかし、ダウンキャストの場合は、オブジェクトが実際に正しい派生型の場合にのみ成功します。
F#では、アップキャストをする際には :> 演算子を利用し、ダウンキャストする際には :?> 演算子を利用します。
サンプルでみるアップキャスト
多くのオブジェクト指向言語では、アップキャストは暗黙的に行われます。しかし、F#では、規則が少し異なります。オブジェクト型のメソッドに引数を渡すと、アップキャストが自動的に適用されます。ただし、モジュール内のlet束縛されている関数の場合は、パラメータがフレキシブル型で宣言されていない限り、アップキャストは自動では行われません。
:> 演算子でのキャスト成功は、コンパイル時に型が決定されていることを意味し、静的にキャストが行われます。つまり、アップキャスト利用時にコンパイルが正常にされた場合、それは有効なキャストであり、実行時に失敗する可能性はありません。
アップキャストをしたい場合に、:> 演算子ではなく、upcast 演算子を利用することも可能です。upcast演算子は以下のような構文となっています。
upcast expression
upcast演算を使用すると、コンパイラはコンテキストから変換先の型を推測しようとします。コンパイラが変換先の型を判別できない場合、コンパイルエラーとなります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ========================================================= | |
// アップキャストのサンプル | |
// ========================================================= | |
// 基底クラス | |
type Base () = class | |
abstract member Function: unit -> unit | |
default x.Function () = printfn "default: Base.Function()" | |
end | |
// 派生クラス | |
type Derived () = class | |
inherit Base () | |
override x.Function () = printfn "Derived.Function()" | |
end | |
// 派生クラスをインスタンス化 | |
let d1:Derived = new Derived () | |
// Baseクラスへアップキャスト(1) | |
let base1 = d1 :> Base | |
// Baseクラスへアップキャスト(2) | |
let base2:Base = upcast d1 | |
サンプルでみるダウンキャスト
:?> 演算子でのキャスト成否は実行時に決定されます。つまり、動的にキャストが行われます。:?> 演算子でのキャストはコンパイル時にはチェックされません。しかし、実行時には指定された方へのキャストをしようと試みます。オブジェクトがキャスト先の型と互換性がある場合に、キャストが成功します。互換性がない場合には、InvalidCastException が発生します。
ダウンキャストをしたい場合に、:?> 演算子ではなく、downcast 演算子を利用することも可能です。downcast演算子は以下のような構文となっています。
downcast expression
以下は、ダウンキャストの簡単なサンプルになります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ========================================================= | |
// ダウンキャストのサンプル | |
// ========================================================= | |
// 基底クラス | |
type Base () = class | |
abstract member Function: unit -> unit | |
default x.Function () = printfn "default: Base.Function()" | |
end | |
// 派生クラス | |
type Derived () = class | |
inherit Base () | |
override x.Function () = printfn "Derived.Function()" | |
end | |
// 基底クラスをインスタンス化 | |
let base1:Base = new Base () | |
// Derivedクラスへダウンキャスト(1) | |
let d1 = base1 :?> Derived | |
// Derivedクラスへダウンキャスト(2) | |
let d2:Derived = downcast base1 | |