構造体は、少量のデータと単純な動作を持つ型のクラスよりも効率的なコンパクトなオブジェクト型です。
構文
[ 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
属性を省略できるため、頻繁に使用されます。
StructAttribute
はStruct
に省略できます。
前の構文の 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
IsByRefLike
は Struct
を意味しません。 両方とも型に存在する必要があります。
F# の "byref
のような" 構造体は、スタック バインド値型です。 マネージド ヒープには割り当てられません。
byref
に似た構造体は、有効期間と非キャプチャに関する一連の強力なチェックで適用されるため、高パフォーマンスプログラミングに役立ちます。 ルールは次のとおりです。
- これらは、関数パラメーター、メソッド パラメーター、ローカル変数、メソッドの戻り値として使用できます。
- クラスまたは通常の構造体の静的メンバーまたはインスタンス メンバーにすることはできません。
- クロージャ コンストラクト (
async
メソッドまたはラムダ式) ではキャプチャできません。 - ジェネリック パラメーターとして使用することはできません。
これらのルールは使用を非常に強く制限しますが、安全な方法でハイパフォーマンス コンピューティングの約束を果たすために行われます。
ReadOnly 構造体
IsReadOnlyAttribute属性を使用して構造体に注釈を付けることができます。 例えば次が挙げられます。
[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
member x.Count1 = count1
member x.Count2 = count2
IsReadOnly
は Struct
を意味しません。
IsReadOnly
構造体を持つには、両方を追加する必要があります。
この属性を使用すると、F# と C# がそれぞれ inref<'T>
と in ref
として扱うことを知らせるメタデータが生成されます。
読み取り専用構造体内で変更可能な値を定義すると、エラーが発生します。
構造体レコードと判別共用体
レコードと判別共用体は、[<Struct>]
属性を持つ構造体として表すことができます。 詳細については、各記事を参照してください。
こちらも参照ください
.NET