プロパティ
プロパティは、getとset、getのみ、あるいはsetのみを定義できます。getとsetに異なる属性とアクセス修飾子を設定することも可能です。
プロパティのデフォルトのアクセス修飾子はpublicです。メソッド同様、staticなプロパティを作成することができます。Staticなプロパティを宣言する際には、セルフ識別子は省略します。
(1)プロパティの定義
プロパティをget、あるいはsetのみ設定したい場合は、下記の構文から片方の記述を取り除きます。
// getとsetに統一したアクセス修飾子が指定
[属性]
[static] member [アクセス修飾子] [セルフ識別子.]プロパティ名
with [アクセス修飾子] get() =
getファンクション本体
and [アクセス修飾子] set parameter =
setファンクション本体
// getとsetにそれぞれ属性とアクセス修飾子を指定
[get用属性]
[static] member [get用アクセス修飾子] [セルフ識別子.]プロパティ名 =
getファンクション本体
[set用属性]
[static] member [set用アクセス修飾子] [セルフ識別子.]PropertyName
with set parameter =
setファンクション本体
F#Beta2では、プロパティ用の属性は未サポートですので、属性に関する詳細な説明は今回は省略します。
//クラスのメンバーとしてプロパティを宣言
type testClass() = class
let mutable color1 = "red"
let mutable color2 = "red"
member this.Color1
with get() = color1
and set(value) = color1 <- value
//privateなプロパティの作成
member private this.Color2
with get() = color2
and set(value) = color2 <- value
end;;
//呼び出し
let testObj3 = new testClass()
//setterには代入演算子を使用して値を設定する
testObj3.Color1 <- "Blue"
printf "%s" testObj3.Color1;;
//Color2はprivateなのでアクセスできない。
testObj3.Color2 <- "Red"
▼
type testClass =
class
new : unit -> testClass
val mutable private color1: string
val mutable private color2: string
member Color1 : string
member private Color2 : string
member Color1 : string with set
member private Color2 : string with set
end
> Blue
val testObj3 : testClass
> //privateなのでエラーが出る。
testObj3.Color2 <- "Red";;
^^^^^^^^
stdin(244,1): error FS0191: The member or object constructor 'Color2' is not accessible. Private members may only be accessed from within the declaring type. Protected members may only be accessed from an extending type and may not be accessed from inner lambda expressions
(2)バッキングストア
C#では、実際のプロパティのデータを、バッキングストアと呼ばれるprivateのフィールドに保存し、そこを参照するようにします。つまり、privateに設定されたフィールドはプロパティの呼び出しによってのみ、変更が可能になります。
private int prop = 3; //バッキングストア
public int Prop
{
get { return prop; }
set { prop = value; }
}
しかし、この手法はよく使われるため、C#3.0以降、下記のように省略して書けるようになりました。「自動プロパティ」として知られているものです。
public string Prop { get; set; }
F#にはこのバッキングストアを暗黙的に作成したり、自動プロパティに該当する機能がありません。従って、明示的にバッキングストアを定義しなくてはなりません。F#では、let 束縛とmutableで、明示的に下記のようにバッキングストアを作成することができます。
type testClass(a : string) =
let mutable prop = a //バッキングストア
member this.Prop
with get() = prop
and set(value) = prop <- value
コンストラクタの追加
プライマリ以外にコンストラクタを宣言したい場合にはnewキーワードを使用します。
new(パラメーターリスト) = コンストラクタボディ(本体)
追加されたコンストラクタ(下記のリスト15ではパラメータを受け取らないコンストラクタ)はコンストラクタボディ部分で、プライマリコンストラクタ(リスト15ではintのパラメーターを2つ受け取るコンストラクタ)を呼び出す必要があります。つまり、最初に記述されたletバインドとdo式はいかなるインスタンスが作成される場合にも実行されるということです。
type testClass (a: int, b: int) =
let mutable c = a + b
do printfn "%d" c
new() =
testClass (0, 0)
new(e: string) =
testClass (10, 20)
then
printfn "%s" e;;
//パラメータを変えてインスタンスを作成してみる
let testObj = new testClass ();;
let testObj2 = new testClass (3, 4);;
let testObj3 = new testClass ("Hello");;
▼
type testClass =
class
new : unit -> testClass
new : e:string -> testClass
new : a:int * b:int -> testClass
end
>//パラメータなしの場合
0
val testObj : testClass
>//パラメータが2つ、int型の場合
7
val testObj2 : testClass
>//パラメータが1つ、string型の場合
30
Hello
val testObj3 : testClass
まとめ
今回はF#におけるオブジェクト指向の基本について紹介しました。次回は、今回解説しました基本機能を使用して、F#固有かつ、若干応用の混じったオブジェクト指向機能について解説したいと思います。
