キャストと変換 (F#)
このトピックでは、F# での型変換のサポートについて説明します。
数値型
F# には、整数型と浮動小数点型の間など、各種のプリミティブ型の間で算術変換を行うための変換演算子が用意されています。 整数変換演算子と char 変換演算子にはチェック形式と非チェック形式がありますが、浮動小数点変換演算子と enum 変換演算子にはありません。 非チェック形式は Microsoft.FSharp.Core.Operators で定義されており、チェック形式は Microsoft.FSharp.Core.Operators.Checked で定義されています。 チェック形式ではオーバーフローがチェックされ、結果値が対象の型の範囲を超えた場合にランタイム例外が生成されます。
これらの各演算子には、変換先の型の名前と同じ名前が付けられています。 たとえば、次のコードでは型が明示的に指定されていますが、byte は 2 つの異なる意味で使用されています。 1 つ目の byte は型を表し、2 つ目の byte は変換演算子を表しています。
let x : int = 5
let b : byte = byte x
次の表に、F# で定義されている変換演算子を示します。
[演算子] |
Description |
---|---|
byte |
バイト (8 ビットの符号なしの型) に変換します。 |
sbyte |
符号付きバイトに変換します。 |
int16 |
16 ビット符号付き整数に変換します。 |
uint16 |
16 ビット符号なし整数に変換します。 |
int32, int |
32 ビット符号付き整数に変換します。 |
uint32 |
32 ビット符号なし整数に変換します。 |
int64 |
64 ビット符号付き整数に変換します。 |
uint64 |
64 ビット符号なし整数に変換します。 |
nativeint |
ネイティブ整数に変換します。 |
unativeint |
符号なしネイティブ整数に変換します。 |
float, double |
64 ビット IEEE 倍精度浮動小数点数に変換します。 |
float32, single |
32 ビット IEEE 単精度浮動小数点数に変換します。 |
decimal |
System.Decimal に変換します。 |
char |
System.Char (Unicode 文字) に変換します。 |
enum |
列挙型に変換します。 |
組み込みのプリミティブ型に加えて、適切なシグネチャを持つ op_Explicit メソッドまたは op_Implicit メソッドを実装する型でも、これらの演算子を使用できます。 たとえば、int 変換演算子は、パラメーターとして型を受け取って int を返す静的メソッド op_Explicit を備える任意の型で使用できます。 戻り値の型によってメソッドをオーバーロードすることはできないというのが一般的な規則ですが、特別な例外として、 op_Explicit および op_Implicit ではこれを実行できます。
列挙型
enum 演算子は変換先の enum の型を表す型パラメーターを 1 つ受け取るジェネリック演算子です。 この演算子を使用して列挙型への変換を行うと、型推論によって変換先の enum の型が決定されます。 次の例の col1 変数は明示的には指定されていませんが、その型は、後半に記述されている等値テストから推論されます。 これにより、Color 列挙型に変換しようとしていることをコンパイラが推論できます。 また、次の例の col2 のように、型の注釈を指定することもできます。
type Color =
| Red = 1
| Green = 2
| Blue = 3
// The target type of the conversion is determined by type inference.
let col1 = enum 1
// The target type is supplied by a type annotation.
let col2 : Color = enum 2
do
if (col1 = Color.Red) then
printfn "Red"
また、次のコードのように型パラメーターとしてターゲットの列挙体を、明示的に指定できます:
let col3 = enum<Color> 3
列挙の基になる型が変換元の型と互換性がある場合にのみ列挙のキャストが機能することに注意してください。 次のコードでは、変換は int32 と uint32間の一貫性をコンパイルしません。
// Error: types are incompatible
let col4 : Color = enum 2u
詳細については、「列挙型 (F#)」を参照してください。
オブジェクト型のキャスト
オブジェクト階層内の型の間での変換は、オブジェクト指向プログラミングでは必要不可欠です。 変換の基本的な種類には、上位へのキャスト (アップキャスト) と下位へのキャスト (ダウンキャスト) の 2 つがあります。 上位階層へのキャストとは、派生オブジェクト参照からベース オブジェクト参照にキャストすることです。 このキャストは、基本クラスが派生クラスの継承階層内にある限り、実行できることが保証されています。 下位階層へのキャストとは、ベース オブジェクト参照から派生オブジェクト参照にキャストすることであり、オブジェクトが実際には目的の変換先の型 (派生型) のインスタンスであるか、変換先の型から派生した型である場合にのみ成功します。
F# には、これらの種類の変換用に演算子が用意されています。 :> 演算子は上位階層へのキャストを行い、:?> 演算子は下位階層へのキャストを行います。
アップキャスト
多くのオブジェクト指向言語では、アップキャストが暗黙で行われますが、F# では若干規則が異なります。 アップキャストは、引数をオブジェクト型でメソッドに渡すときに自動的に適用されます。 ただし、モジュール内で let 束縛された関数の場合は、パラメーターの型がフレキシブル型として宣言されていない限り、アップキャストは自動的には行われません。 詳細については、「フレキシブル型 (F#)」を参照してください。
:> 演算子は静的なキャストを実行します。これは、キャストが成功するかどうかがコンパイル時に決まることを意味しています。 :> を使用したキャストのコンパイルが成功した場合、そのキャストは有効であり、実行時に失敗することはありません。
upcast 演算子を使用して、このような変換を実行することもできます。 次の式では、上位階層への変換を指定しています。
upcast expression
upcast 演算子を使用する場合は、コンパイラがコンテキストから変換先の型を推論しようとします。 コンパイラは、変換先の型を決定できない場合はエラーを報告します。
ダウンキャスト
:?> 演算子は動的なキャストを実行します。これは、キャストが成功するかどうかが実行時に決まることを意味しています。 :?> 演算子を使用したキャストはコンパイル時にはチェックされません。指定した型へのキャストは実行時に試行されます。 オブジェクトが変換先の型と互換性がある場合、キャストは成功します。 オブジェクトが変換先の型と互換性がない場合は、ランタイムにより InvalidCastException が発生します。
downcast 演算子を使用して、動的な型変換を実行することもできます。 次の式では、下位階層への変換を指定しています。変換先の型は、プログラム コンテキストから推論された型になります。
downcast expression
upcast 演算子を使用すると、コンパイラが特定の変換先の型をコンテキストから推論できない場合に、エラーが報告されます。
次のコードは、:> 演算子と :?> 演算子の使用例を示しています。 このコードは、変換が成功することが明らかな場合は、:?> 演算子を使用する方法が最適であることを示しています。これは、変換が失敗すると InvalidCastException がスローされるためです。 変換が成功するかどうかが不明な場合には、match 式を使用して型テストを行うことをお勧めします。型テストを行うと、例外の生成によるオーバーヘッドを回避できるためです。
type Base1() =
abstract member F : unit -> unit
default u.F() =
printfn "F Base1"
type Derived1() =
inherit Base1()
override u.F() =
printfn "F Derived1"
let d1 : Derived1 = Derived1()
// Upcast to Base1.
let base1 = d1 :> Base1
// This might throw an exception, unless
// you are sure that base1 is really a Derived1 object, as
// is the case here.
let derived1 = base1 :?> Derived1
// If you cannot be sure that b1 is a Derived1 object,
// use a type test, as follows:
let downcastBase1 (b1 : Base1) =
match b1 with
| :? Derived1 as derived1 -> derived1.F()
| _ -> ()
downcastBase1 base1
ジェネリック演算子である downcast と upcast は、引数と戻り値の型を決定する際に型推論を使用するため、上記のコードで次のように置き換えることができます。
let base1 = d1 :> Base1
with
base1 = upcast d1
前のコードの引数の型と戻り値の型は、それぞれ Derived1 と Base1 になります。
型テストの詳細については、「match 式 (F#)」を参照してください。