明示的なフィールド: val キーワード (F#)
val キーワードを使用すると、クラス型や構造体型のフィールドを初期化せずに宣言することができます。 この方法で宣言されたフィールドを、明示的なフィールドと呼びます。 val のキーワードのもう一つの使用は自動実装プロパティを宣言する member のキーワードとともにあります。 自動実装プロパティの詳細については、プロパティ (F#)を参照してください。
val [ mutable ] [ access-modifier ] field-name : type-name
解説
クラス型や構造体型のフィールドを定義するには、通常、let 束縛を使用します。 ただし、let 束縛はクラス コンストラクターの一部として初期化する必要があり、それが常に可能または必要であるとは限りません。または、それが望ましくない場合もあります。 初期化されていないフィールドが必要な場合は、val キーワードを使用できます。
明示的なフィールドは、static である場合も、static でない場合もあります。 access-modifier は、public にすることも、private にすることも、internal にすることもできます。 既定値は public です。 常に private であるクラスの let 束縛とは、この点が異なります。
プライマリ コンストラクターを持つクラス型の明示的なフィールドには、DefaultValue 属性が必要です。 この属性は、フィールドが 0 に初期化されることを示します。 したがって、フィールドの型がゼロ初期化をサポートしている必要があります。 型が次のいずれかに当てはまる場合は、ゼロ初期化がサポートされます。
値 0 を持つプリミティブ型。
通常値、異常値、または値の表現として null 値をサポートする型。 これには、クラス、タプル、レコード、関数、インターフェイス、.NET 参照型、unit 型、および判別共用体型が含まれます。
.NET 値型。
すべてのフィールドで既定値 0 がサポートされている構造体。
注意
メモ は、.NET Framework 名前空間 System.ComponentModel 同じ名前を持つ属性が含まれています。この属性については、DefaultValueAttributeを参照してください。
次のコードは、プライマリ コンストラクターを持つクラスで明示的なフィールドを使用する方法を示しています。比較のために、let 束縛の使用方法も示します。 let バインドされたフィールド myInt1 が private であることに注意してください。 let バインドされたフィールド myInt1 をメンバー メソッドから参照する際には、自己識別子 this は必要ありません。 ただし、明示的なフィールド myInt2 および myString を参照する際には、自己識別子が必要です。
type MyType() =
let mutable myInt1 = 10
[<DefaultValue>] val mutable myInt2 : int
[<DefaultValue>] val mutable myString : string
member this.SetValsAndPrint( i: int, str: string) =
myInt1 <- i
this.myInt2 <- i + 1
this.myString <- str
printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)
let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"
printfn "%d %s" (myObject.myInt2) (myObject.myString)
出力は次のとおりです。
11 12 abc
30 def
次のコードは、プライマリ コンストラクターのないクラスで明示的なフィールドを使用する方法を示しています。 この場合は、DefaultValue 属性は必要ありませんが、型で定義されているコンストラクターですべてのフィールドが初期化される必要があります。
type MyClass =
val a : int
val b : int
// The following version of the constructor is an error
// because b is not initialized.
// new (a0, b0) = { a = a0; }
// The following version is acceptable because all fields are initialized.
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)
出力は 35 22 になります。
次のコードは、構造体で明示的なフィールドを使用する方法を示しています。 構造体は値型であるため、フィールドの値を 0 に設定する既定のコンストラクターが自動的に含まれます。 したがって、DefaultValue 属性は必要ありません。
type MyStruct =
struct
val mutable myInt : int
val mutable myString : string
end
let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"
printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)
出力は 11 xyz になります。
明示的なフィールドは、日常的に使用するためのものではありません。 通常、可能な場合は、明示的なフィールドではなくクラスの let 束縛を使用してください。 明示的なフィールドは、特定の相互運用のシナリオ (ネイティブ API に対するプラットフォーム呼び出しで使用される構造体を定義する場合など) や、COM 相互運用のシナリオで使用できます。 詳細については、「外部関数 (F#)」を参照してください。 プライマリ コンストラクターを持たないクラスを生成する F# コード ジェネレーターを使用している場合にも、明示的なフィールドが必要になることがあります。 そのほかに、スレッドの静的変数や、それに似た構成要素に対しても使用できます。 詳細については、「ThreadStaticAttribute」を参照してください。
キーワード member val が型定義にまとめて表示されると、自動的に実装されたプロパティの定義です。 詳細については、「プロパティ (F#)」を参照してください。