コンストラクター (F#)
このトピックでは、コンストラクターを定義および使用して、クラス オブジェクトと構造体オブジェクトを作成して初期化する方法について説明します。
クラス オブジェクトの構築
クラス型のオブジェクトにはコンストラクターがあります。 コンストラクターは 2 種類あります。 1 つは、プライマリ コンストラクターです。このコンストラクターのパラメーターは、型名の直後のかっこ内に記述されます。 もう 1 つの、省略可能な追加のコンストラクターは、new キーワードを使用して指定します。 このような追加のコンストラクターでは、プライマリ コンストラクターを呼び出す必要があります。
プライマリ コンストラクターには、クラス定義の先頭にある let 束縛と do 束縛が含まれています。 let 束縛は、クラス内のプライベートのフィールドおよびメソッドを宣言します。do 束縛は、コードを実行します。 クラス コンストラクターの let 束縛の詳細については、「クラス内の let 束縛 (F#)」を参照してください。 コンストラクターの do 束縛の詳細については、「クラス内の do 束縛 (F#)」を参照してください。
プライマリ コンストラクターと追加のコンストラクターのどちらを呼び出すかに関係なく、new 式と、省略可能な new キーワードを使用することにより、オブジェクトを作成できます。 オブジェクトはコンストラクター引数と共に初期化します。それには、コンマで区切った引数をかっこ内に順番に並べるか、または名前付き引数と値をかっこ内で使用します。 また、オブジェクトの構築時にオブジェクトのプロパティを設定することもできます。この場合は、名前付きのコンストラクター引数を使用する場合と同様に、プロパティ名を使用して値を代入します。
次のコードは、コンストラクターがあるクラスと、オブジェクトのさまざまな作成方法を示します。
// This class has a primary constructor that takes three arguments
// and an additional constructor that calls the primary constructor.
type MyClass(x0, y0, z0) =
let mutable x = x0
let mutable y = y0
let mutable z = z0
do
printfn "Initialized object that has coordinates (%d, %d, %d)" x y z
member this.X with get() = x and set(value) = x <- value
member this.Y with get() = y and set(value) = y <- value
member this.Z with get() = z and set(value) = z <- value
new() = MyClass(0, 0, 0)
// Create by using the new keyword.
let myObject1 = new MyClass(1, 2, 3)
// Create without using the new keyword.
let myObject2 = MyClass(4, 5, 6)
// Create by using named arguments.
let myObject3 = MyClass(x0 = 7, y0 = 8, z0 = 9)
// Create by using the additional constructor.
let myObject4 = MyClass()
出力は次のとおりです。
Initialized object that has coordinates (1, 2, 3)
Initialized object that has coordinates (4, 5, 6)
Initialized object that has coordinates (7, 8, 9)
Initialized object that has coordinates (0, 0, 0)
構造体の構築
構造体は、クラスのすべての規則に従います。 したがって、プライマリ コンストラクターを定義し、new キーワードを使用して追加のコンストラクターを指定できます。 ただし、構造体とクラスには、重要な違いが 1 つあります。それは、構造体には、プライマリ コンストラクターが定義されていない場合でも、既定のコンストラクター (引数を持たないコンストラクター) があるということです。 既定のコンストラクターは、すべてのフィールドを型の既定値 (通常はゼロまたはそれに相当する値) に初期化します。 構造体に対して定義するコンストラクターには、既定のコンストラクターとの競合を避けるために、少なくとも 1 つの引数を含める必要があります。
また、構造体は多くの場合、val キーワードを使用して作成されたフィールドを持ちます。クラスもこれらのフィールドを持つことができます。 val キーワードを使用して定義されたフィールドを持つ構造体およびクラスは、次のコードに示すように、追加のコンストラクター内でレコード式を使用して初期化することもできます。
type MyStruct =
struct
val X : int
val Y : int
val Z : int
new(x, y, z) = { X = x; Y = y; Z = z }
end
let myStructure1 = new MyStruct(1, 2, 3)
詳細については、「明示的なフィールド: val キーワード (F#)」を参照してください。
コンストラクターでの副作用の実行
クラスのプライマリ コンストラクターでは、do 束縛でコードを実行できます。 しかし、do 束縛のない追加のコンストラクターでコードを実行する必要がある場合もあります。 これを行うには、then キーワードを使用します。
// Executing side effects in the primary constructor and
// additional constructors.
type Person(nameIn : string, idIn : int) =
let mutable name = nameIn
let mutable id = idIn
do printfn "Created a person object."
member this.Name with get() = name and set(v) = name <- v
member this.ID with get() = id and set(v) = id <- v
new() =
Person("Invalid Name", -1)
then
printfn "Created an invalid person object."
let person1 = new Person("Humberto Acevedo", 123458734)
let person2 = new Person()
プライマリ コンストラクターの副作用は依然として実行されます。 したがって、出力は次のようになります。
Created a person object.
Created a person object.
Created an invalid person object.
コンストラクター内の自己識別子
他のメンバーでは、各メンバーの定義で現在のオブジェクトの名前を指定します。 また、コンストラクターのパラメーターの直後に as キーワードを記述して、クラス定義の最初の行に自己識別子を置くこともできます。 この構文を次の例に示します。
type MyClass1(x) as this =
// This use of the self identifier produces a warning - avoid.
let x1 = this.X
// This use of the self identifier is acceptable.
do printfn "Initializing object with X =%d" this.X
member this.X = x
追加のコンストラクターでは、コンストラクターのパラメーターの直後に as 句を置くことで、自己識別子を定義できます。 この構文を次の例に示します。
type MyClass2(x : int) =
member this.X = x
new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X
完全に定義される前のオブジェクトを使用すると、問題が発生することがあります。 そのため、自己識別子を使用すると、コンパイラで警告が生成され、オブジェクトの初期化前にオブジェクトのメンバーへのアクセスが行われていないことを確認するための追加チェックが挿入されます。 自己識別子は、プライマリ コンストラクターの do 束縛内、または追加のコンストラクターの then キーワードの後でのみ使用する必要があります。
自己識別子の名前は、this である必要はありません。 任意の有効な識別子を使用できます。
初期化時のプロパティへの値の代入
property = value の形式の一連の代入を、コンストラクターの引数リストに追加すると、初期化コード中のクラス オブジェクトのプロパティに値を代入できます。 次のコード例にこれを示します。
type Account() =
let mutable balance = 0.0
let mutable number = 0
let mutable firstName = ""
let mutable lastName = ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(AccountNumber=8782108,
FirstName="Darren", LastName="Parker",
Balance=1543.33)
次に示す、前のコードのバージョンは、通常の引数、省略可能な引数、およびプロパティ設定を組み合わせた 1 つのコンストラクター呼び出しを表します。
type Account(accountNumber : int, ?first: string, ?last: string, ?bal : float) =
let mutable balance = defaultArg bal 0.0
let mutable number = accountNumber
let mutable firstName = defaultArg first ""
let mutable lastName = defaultArg last ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(8782108, bal = 543.33,
FirstName="Raman", LastName="Iyer")
静的コンストラクターまたは型コンストラクター
オブジェクトを作成するためのコードを指定するだけでなく、型が最初に使用される前に型レベルで初期化を行うために実行される静的な let 束縛と do 束縛をクラス型で作成することもできます。 詳細については、「クラス内の let 束縛 (F#)」および「クラス内の do 束縛 (F#)」を参照してください。