構造体
"構造体" はコンパクトなオブジェクト型であり、データが少量で動作が単純な型のクラスよりも効率が良い場合があります。
構文
[ 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
宣言がゼロまたは null に初期化されます。 このため、暗黙のコンストラクター (宣言で構造体名の直後に指定されるパラメーター) を含む構造体では、val
宣言に DefaultValue
属性で注釈を付ける必要があります。 定義されたコンストラクターを含む構造体でも、ゼロ初期化がサポートされます。 したがって、DefaultValue
属性は、このようなゼロ値がフィールドに対して有効であることの宣言になります。 構造体の暗黙的なコンストラクターでは動作は実行されません。これは、let
バインディングと do
バインディングがその型では許可されていないためですが、渡された暗黙のコンストラクターのパラメーター値はプライベート フィールドとして使用できます。
明示的なコンストラクターにフィールド値の初期化が含まれる場合があります。 明示的なコンストラクターを含む構造体がある場合も、ゼロ初期化がサポートされます。ただし、明示的なコンストラクターと競合するため、DefaultValue
宣言では val
属性を使用しません。 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
に似たセマンティクスに従うことができる独自の構造体を定義することができます。詳細については、「byref」を参照してください。 これは 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