Структуры
Структура — это компактный тип объекта, который может быть более эффективным, чем класс для типов с небольшим объемом данных и простым поведением.
Синтаксис
[ 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
Замечания
Структуры — это типы значений, что означает, что они хранятся непосредственно в стеке или, когда они используются в качестве полей или элементов массива, встроенные в родительский тип. В отличие от классов и записей структуры имеют семантику pass-by-value (передача по значению). Это означает, что они используются в основном для небольших объемов данных, которые часто используются и копируются.
В предыдущем синтаксисе показаны две формы. Первая не является упрощенным синтаксисом, но, тем не менее, используется довольно часто, так как при использовании ключевых слов struct
и end
можно опустить атрибут StructAttribute
, который есть во второй форме. StructAttribute
можно сократить до Struct
.
Тип-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
семантике: дополнительные сведения см. в разделе 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
. Оба должны присутствовать в типе.
Структуру типа "byref
как" в F# — это тип значения, привязанного к стеку. Он никогда не выделяется в управляемой куче. Например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>]
. Дополнительные сведения см. в каждой статье.