この記事では、コンストラクターを定義して使用して、クラスオブジェクトと構造体オブジェクトを作成および初期化する方法について説明します。
クラス オブジェクトの構築
クラス型のオブジェクトにはコンストラクターがあります。 コンストラクターには 2 種類あります。 1 つは、型名の直後にかっこで囲まれたパラメーターを持つプライマリ コンストラクターです。 必要に応じて、 new
キーワードを使用して追加のコンストラクターを指定できます。 このような追加コンストラクターは、プライマリ コンストラクターを呼び出す必要があります。
プライマリ コンストラクターには、クラス定義の先頭に表示される let
バインドと do
バインドが含まれています。
let
バインディングは、クラスのプライベート フィールドとメソッドを宣言します。do
バインドはコードを実行します。 クラス コンストラクターのバインドlet
の詳細については、「クラスのバインドのlet
」を参照してください。 コンストラクターのバインドdo
の詳細については、「クラスのバインドのdo
」を参照してください。
呼び出すコンストラクターがプライマリ コンストラクターか追加コンストラクターかに関係なく、オプションの 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 つの重要な違いがあります。構造体には、プライマリ コンストラクターが定義されていない場合でも、パラメーターなしのコンストラクター (つまり、引数のないコンストラクター) を持つことができます。 パラメーターなしのコンストラクターは、すべてのフィールドをその型の既定値 (通常は 0 または同等) に初期化します。 構造体に対して定義するコンストラクターは、パラメーターなしのコンストラクターと競合しないように、少なくとも 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
キーワード」を参照してください。
コンストラクターでの副作用の実行
クラスのプライマリ コンストラクターは、 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.
別のdo
の代わりにthen
が必要な理由は、do
キーワードが、追加のコンストラクターの本体に存在する場合にunit
を返す式を区切る標準的な意味を持っているからです。 これは、プライマリ コンストラクターのコンテキストでのみ特別な意味を持ちます。
コンストラクター内の自己識別子
他のメンバーでは、各メンバーの定義で現在のオブジェクトの名前を指定します。 コンストラクター パラメーターの直後に 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")
継承されたクラスのコンストラクター
コンストラクターを持つ基底クラスから継承する場合は、inherit 句でその引数を指定する必要があります。 詳細については、「 コンストラクターと継承」を参照してください。
静的コンストラクターまたは型コンストラクター
オブジェクトを作成するためのコードを指定するだけでなく、静的 let
および do
バインディングは、型が型レベルで初期化を実行するために最初に使用される前に実行されるクラス型で作成できます。 詳細については、「クラスのバインドのlet
」および「クラスのバインドのdo
」を参照してください。
こちらも参照ください
.NET