次の方法で共有


構造体

構造体は、少量のデータと単純な動作を持つ型のクラスよりも効率的なコンパクトなオブジェクト型です。

構文

[ attributes ]
type [accessibility-modifier] type-name =
    struct
        type-definition-elements-and-members
    end
// or
[ attributes ]
[<StructAttribute>]
type [accessibility-modifier] type-name =
    type-definition-elements-and-members

注釈

構造体は 値型です。つまり、スタックに直接格納されるか、フィールドまたは配列要素として使用される場合は、親型にインラインで格納されます。 クラスやレコードとは異なり、構造体には値渡しセマンティクスがあります。 これは、主に、頻繁にアクセスおよびコピーされるデータの小さな集計に役立つことを意味します。

前の構文では、2 つの形式が示されています。 1 つ目は軽量構文ではありませんが、 struct キーワードと end キーワードを使用すると、2 番目の形式で表示される StructAttribute 属性を省略できるため、頻繁に使用されます。 StructAttributeStructに省略できます。

前の構文の type-definition-elements-and-members は、メンバーの宣言と定義を表します。 構造体にはコンストラクターと変更可能なフィールドと変更できないフィールドを含めることができます。また、メンバーとインターフェイスの実装を宣言することもできます。 詳細については、「 メンバー」を参照してください。

構造体は継承に参加できず、 let バインドまたは do バインディングを含めることはできません。また、独自の型のフィールドを再帰的に含めることはできません (ただし、独自の型を参照する参照セルを含めることができます)。

構造体では let バインドが許可されないため、 val キーワードを使用して構造体のフィールドを宣言する必要があります。 val キーワードは、フィールドとその型を定義しますが、初期化は許可しません。 代わりに、 val 宣言は 0 または null に初期化されます。 このため、暗黙的なコンストラクターを持つ構造体 (つまり、宣言内の構造体名の直後に指定されるパラメーター) では、 val 宣言に DefaultValue 属性で注釈を付ける必要があります。 定義されたコンストラクターを持つ構造体では、引き続きゼロ初期化がサポートされます。 したがって、 DefaultValue 属性は、このような 0 個の値がフィールドに対して有効であるという宣言です。 構造体の暗黙的なコンストラクターは、型に対して let バインドと do バインドが許可されていないため、アクションを実行しませんが、渡される暗黙的なコンストラクター パラメーター値はプライベート フィールドとして使用できます。

明示的なコンストラクターには、フィールド値の初期化が含まれる場合があります。 明示的なコンストラクターを持つ構造体がある場合でも、ゼロ初期化がサポートされます。ただし、明示的なコンストラクターと競合するため、val宣言ではDefaultValue属性を使用しません。 val宣言の詳細については、「明示的なフィールド: val キーワード」を参照してください。

属性とアクセシビリティ修飾子は構造体で使用でき、他の型の場合と同じ規則に従います。 詳細については、「属性とアクセス制御参照してください。

次のコード例は、構造体の定義を示しています。

// In Point3D, three immutable values are defined.
// x, y, and z will be initialized to 0.0.
type Point3D =
    struct
        val x: float
        val y: float
        val z: float
    end

// In Point2D, two immutable values are defined.
// It also has a member which computes a distance between itself and another Point2D.
// Point2D has an explicit constructor.
// You can create zero-initialized instances of Point2D, or you can
// pass in arguments to initialize the values.
type Point2D =
    struct
        val X: float
        val Y: float
        new(x: float, y: float) = { X = x; Y = y }

        member this.GetDistanceFrom(p: Point2D) =
            let dX = (p.X - this.X) ** 2.0
            let dY = (p.Y - this.Y) ** 2.0

            dX + dY |> sqrt
    end

ByRefLike 構造体

byrefのようなセマンティクスに準拠できる独自の構造体を定義できます。詳細については、Byrefs を参照してください。 これを行うには、IsByRefLikeAttribute 属性を使用します。

open System
open System.Runtime.CompilerServices

[<IsByRefLike; Struct>]
type S(count1: Span<int>, count2: Span<int>) =
    member x.Count1 = count1
    member x.Count2 = count2

IsByRefLikeStructを意味しません。 両方とも型に存在する必要があります。

F# の "byref のような" 構造体は、スタック バインド値型です。 マネージド ヒープには割り当てられません。 byrefに似た構造体は、有効期間と非キャプチャに関する一連の強力なチェックで適用されるため、高パフォーマンスプログラミングに役立ちます。 ルールは次のとおりです。

  • これらは、関数パラメーター、メソッド パラメーター、ローカル変数、メソッドの戻り値として使用できます。
  • クラスまたは通常の構造体の静的メンバーまたはインスタンス メンバーにすることはできません。
  • クロージャ コンストラクト (async メソッドまたはラムダ式) ではキャプチャできません。
  • ジェネリック パラメーターとして使用することはできません。

これらのルールは使用を非常に強く制限しますが、安全な方法でハイパフォーマンス コンピューティングの約束を果たすために行われます。

ReadOnly 構造体

IsReadOnlyAttribute属性を使用して構造体に注釈を付けることができます。 例えば次が挙げられます。

[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
    member x.Count1 = count1
    member x.Count2 = count2

IsReadOnlyStructを意味しません。 IsReadOnly構造体を持つには、両方を追加する必要があります。

この属性を使用すると、F# と C# がそれぞれ inref<'T>in refとして扱うことを知らせるメタデータが生成されます。

読み取り専用構造体内で変更可能な値を定義すると、エラーが発生します。

構造体レコードと判別共用体

レコード判別共用体は[<Struct>]属性を持つ構造体として表すことができます。 詳細については、各記事を参照してください。

こちらも参照ください