Share via


明示的なフィールド: 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 がサポートされている構造体。

Caution メモ注意

メモ は、.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#)」を参照してください。

参照

関連項目

プロパティ (F#)

クラス内の let 束縛 (F#)

その他の技術情報

メンバー (F#)