(3)valキーワード
letで宣言されたフィールドはコンストラクタ内で宣言・定義されなくてはなりませんが、フィールドによっては必ずしもその場で定義ができるとは限りません。そこで、コンストラクタ内で、まだ定義できないフィールドを宣言するには、letの代わりにvalというキーワードを使用します。letでバインドされたフィールドは常にprivateであり、クラスのメソッドもしくはプロパティ経由でのみアクセスできます。対して、valで宣言されるフィールドはデフォルトでpublicになるため、クラスの外からフィールドを呼ぶ必要がある場合には、valを使用する必要があります。
[static] val [mutable] [アクセス修飾子] フィールド名 : 型
プライマリコンストラクタを持つクラスでvalでフィールドを宣言する場合には、[<DefaultValue>]属性をつける必要があります。プライマリコンストラクタ内でvalを宣言する際にはvalはmutableキーワードとセットで使用される必要があります。
type testClass1(a1 : int, b1 : int) =
let a = a1 + b1
let mutable c = 3
let mutable b = a1 * b1
[<DefaultValue>] val mutable d : int
[<DefaultValue>] val mutable e : string
do printf "%d, %d" a b;;
let testClass1= new testClass1(4, 5)
//cはletで宣言されていてprivateなのでアクセスできない。
//testClass1.c <- 5
//dはvalで宣言されているので大丈夫。
testClass1.d <- 5;;
▼
type testClass1 =
class
new : a1:int * b1:int -> testClass1
val mutable d: int
val mutable e: string
end
> 9, 20
val testClass1 : testClass1
(4)セルフ識別子
セルフ識別子は、C#のthisにあたるものです(注1)。現在のインスタンスを表すときにthis ではなくここで指定した識別子を使用できるようになります。このとき、asキーワードに続き、コンストラクタパラメータの後に指定したセルフ識別子はクラス内で有効になります。
type testClass(testparam) as kore =
let teststr = testparam
//実行中のオブジェクトを表す識別子koreでtestClass内のメソッドを指定
do kore.testMethod()
//member行はメソッドを宣言しています。
//メソッド名の前にメソッド内でのみ有効なセルフ識別子(this)を指定
member this.testMethod() =
printf "test self identifier : %s" teststr
//インスタンス作成
let testItem = testClass("aaa")
//メソッド呼び出し
testItem.testMethod();;
▼
//インスタンス作成に伴うプライマリコンストラクタの処理
test self identifier : aaa
//メソッド呼び出しによる処理
test self identifier : aaa
type testClass =
class
new : testparam:string -> testClass
member testMethod : unit -> unit
end
val testItem : testClass
self identifierに対応する日本語として、セルフ識別子と書きましたがマイクロソフトによる正式な日本語名称は不明です。
(5)ジェネリック型
F#では、ジェネリックな型のパラメータはアポストロフィ(')を前につけて、'a、'Tなどのように表されます。
let testGetFst (a, b) = a;;
▼
val testGetFst : 'a * 'b -> 'a
F#でコードをジェネリックにしたいとき、大抵の場合はコンパイラによる型推論もしくは、自動ジェネリック化機能によって暗黙的にジェネリックになります。自動ジェネリック化機能というのは、コンパイラが提供されたパラメータから型推論できず、またそれらが他の要素の型に依存することがないと判断したときに、ファンクションが複数の種類の型のパラメータで機能するように一般化(ジェネリック化)することです。
例えば、上記の例は2つの要素を持つ組(タプル)を与えられたときに常に1つ目の要素を返す関数ですが、このとき、コンパイラは2つのパラメータが他の要素の型に依存することがないと判断し、パラメータをジェネリック化しています。
しかし、あえて曖昧さをなくすため明示的に指定したい場合には、山括弧(<>)を使用して指定することが可能です。下記のリスト8は、プライマリコンストラクタが受け取る2つのパラメータがジェネリックであるクラスの例です。クラス名の後に山括弧でパラメータを指定します。
type testClass<'a, 'b> (x : 'a, y : 'b) =
let x0 = x
let y0 = y
do printfn "%A %A" x0 y0
//string型とint型のパラメータで初期化
let testItem = testClass<string, int> ("aaa", 5)
//int型とfloat型のパラメータ3で初期化
let testItem2 = testClass<int, float> (3, 3.0);;
▼
"aaa" 5
3 3.0
type testClass<'a,'b> =
class
new : x:'a * y:'b -> testClass<'a,'b>
end
val testItem : testClass<string,int>
val testItem2 : testClass<int,float>
Automatic generalizationに対応する日本語として、自動ジェネリック化と書きましたがマイクロソフトによる正式な日本語名称は不明です。
