F#の組み込み型
この記事では、.NETに組み込まれている標準的な型をF#がどう扱うかを簡単に見ていきます。
F# では、C# と同じ構文を使用してリテラルを表しますが、いくつかの例外があります。
組み込み型は以下のように分類できます。
- その他の型 (
bool,charなど) - 文字列型
- 整数型 (
int、uint、byteなど) - 浮動小数点型 (
float、decimalなど) - ポインタ型 (
IntPtrなど)
以下の表は、プリミティブ型とそのF#キーワード、接尾辞(ある場合)、例、対応する.NET CLR型を示しています。
| オブジェクト | ユニット | 真偽値 | 文字 (Unicode) |
文字 (ASCII) |
|
|---|---|---|---|---|---|
| キーワード | obj | unit | bool | char | byte |
| 接尾辞 | B | ||||
| 例 | let o = obj() | let u = () | true false | 'a' | 'a'B |
| .NET型 | Object | (相当なし) | Boolean | Char | Byte |
オブジェクトとユニットは厳密には.NETのプリミティブ型ではありませんが、網羅性のために含めました。
| 文字列 (Unicode) |
逐語的文字列 (Unicode) |
三重引用符文字列 (Unicode) |
文字列 (ASCII) |
|
|---|---|---|---|---|
| キーワード | string | string | string | byte[] |
| 接尾辞 | ||||
| 例 | "first\nsecond line" | @"C:\name" | """can "contain"" special chars""" | "aaa"B |
| .NET型 | String | String | String | Byte[] |
通常の文字列内では、 \n 、 \t 、 \\ などの特殊文字を使えます。引用符はバックスラッシュでエスケープする必要があります。 \' と \" がその例です。
逐語的文字列では、バックスラッシュは無視されます。これはWindowsのファイル名や正規表現パターンに便利です。ただし、引用符は2つ重ねる必要があります。
三重引用符文字列は、VS2012で新しく導入されました。特殊文字をエスケープする必要がないため、埋め込み引用符を簡単に扱えます。XMLに最適です。
| 8ビット (符号付き) |
8ビット (符号なし) |
16ビット (符号付き) |
16ビット (符号なし) |
32ビット (符号付き) |
32ビット (符号なし) |
64ビット (符号付き) |
64ビット (符号なし) |
任意 精度 |
|
|---|---|---|---|---|---|---|---|---|---|
| キーワード | sbyte | byte | int16 | uint16 | int | uint32 | int64 | uint64 | bigint |
| 接尾辞 | y | uy | s | us | u | L | UL | I | |
| 例 | 99y | 99uy | 99s | 99us | 99 | 99u | 99L | 99UL | 99I |
| .NET型 | SByte | Byte | Int16 | UInt16 | Int32 | UInt32 | Int64 | UInt64 | BigInteger |
BigInteger は、すべてのバージョンのF#で使えます。.NET 4以降では、.NETの基本ライブラリの一部として含まれています。
整数型は16進数や8進数でも表せます。
- 16進数の接頭辞は
0xです。たとえば、0xFFは16進数で255を表します。 - 8進数の接頭辞は
0oです。たとえば、0o377は8進数で255を表します。
浮動小数点型
Section titled “浮動小数点型”| 32ビット 浮動小数点 |
64ビット(デフォルト) 浮動小数点 |
高精度 浮動小数点 |
|
|---|---|---|---|
| キーワード | float32, single | float, double | decimal |
| 接尾辞 | f | m | |
| 例 | 123.456f | 123.456 | 123.456m |
| .NET型 | Single | Double | Decimal |
F#ではデフォルトで float を使いますが、 double も使えることに注意してください。
| ポインタ/ハンドル (符号付き) |
ポインタ/ハンドル (符号なし) |
|
|---|---|---|
| キーワード | nativeint | unativeint |
| 接尾辞 | n | un |
| 例 | 0xFFFFFFFFn | 0xFFFFFFFFun |
| .NET型 | IntPtr | UIntPtr |
組み込みプリミティブ型間のキャスト
Section titled “組み込みプリミティブ型間のキャスト”注:このセクションではプリミティブ型のキャストのみを扱います。クラス間のキャストについては、オブジェクト指向プログラミングのシリーズを参照してください。
F#には直接的な「キャスト」構文はありませんが、型間のキャストを行うヘルパー関数があります。これらのヘルパー関数は型と同じ名前を持ちます。 Microsoft.FSharp.Core 名前空間で見つけることができます。
たとえば、C#では次のように書きます。
var x = (int)1.23var y = (double)1F#では次のように書きます。
let x = int 1.23let y = float 1F#では、数値型に対するキャスト関数しかありません。特に、 bool に対するキャストはなく、 Convert などを使う必要があります。
let x = bool 1 // エラーlet y = System.Convert.ToBoolean(1) // OKボクシングとアンボクシング
Section titled “ボクシングとアンボクシング”C#や他の.NET言語と同様に、プリミティブなintやfloat型は値型であり、クラスではありません。 通常はあまり意識しませんが、特定の状況では問題になることがあります。
まず、単純な例を見てみましょう。以下の例では、 Object 型のパラメータを受け取り、そのまま返す関数を定義します。
int を渡すと、暗黙的にオブジェクトにボクシングされます。テストコードから分かるように、結果は int ではなく object を返します。
// Object型のパラメータを持つ関数を作るlet objFunction (o:obj) = o
// テスト:整数を渡して呼び出すlet result = objFunction 1
// 結果は// val result : obj = 1result が整数ではなくオブジェクトであることは、注意しないと型エラーの原因になることがあります。たとえば、結果を元の値と直接比較することはできません。
let resultIsOne = (result = 1)// error FS0001: この式に必要な型は 'obj' ですが、// ここでは次の型が指定されています 'int'この状況や似たような状況に対処するため、 box キーワードを使ってプリミティブ型を直接オブジェクトに変換できます。
let o = box 1
// 上の比較例を再テストし、ボクシングを使うlet result = objFunction 1let resultIsOne = (result = box 1) // OKオブジェクトをプリミティブ型に戻すには、 unbox キーワードを使います。ただし、 box とは異なり、アンボクシング先の型を指定するか、コンパイラが正確に型推論できるよう十分な情報が必要となります。
// intをボクシングlet o = box 1
// 対象の値の型が分かっている場合let i:int = unbox o // OK
// unboxで明示的に型を指定let j = unbox<int> o // OK
// 型推論が可能なので、型注釈は不要let k = 1 + unbox o // OKしたがって、先ほどの比較の例も unbox を使って行えます。 int 型との比較なので、明示的な型注釈は必要ありません。
let result = objFunction 1let resultIsOne = (unbox result = 1) // OKしかし、十分な型情報を指定しないと、悪名高き「値制限」エラーに遭遇します。
let o = box 1
// 型が指定されていないlet i = unbox o // error FS0030: 値の制限解決方法は、型推論を助けるようにコードを並べ替えるか、どうしても駄目な場合は明示的な型注釈を追加することです。詳しくは型推論に関する記事のトラブルシューティングのまとめを参照してください。
型検出とボクシングの組み合わせ
Section titled “型検出とボクシングの組み合わせ”パラメータの型に基づいてマッチングを行う関数を、 :? 演算子を使って作りたいとします。
let detectType v = match v with | :? int -> printfn "これは整数です" | _ -> printfn "それ以外です"残念ながら、このコードはコンパイルに失敗し、次のエラーが出ます。
// error FS0008: この型 'a から型 int へのランタイム型変換またはランタイム型テストには、// このプログラムの場所の前方にある情報に基づく不確定の型が使用されています。// 実行時の型テストは一部の型では許可されていません。さらなる型注釈が必要です。「実行時の型テストは一部の型では許可されていません。」というメッセージが問題を示しています。
解決方法は、値を「ボクシング」して参照型に換し、その後で型チェックを行うことです。
let detectTypeBoxed v = match box v with // "box v"を使う | :? int -> printfn "これは整数です" | _ -> printfn "それ以外です"
// テストdetectTypeBoxed 1detectTypeBoxed 3.14