Поделиться через


Структуры

Структура — это компактный тип объекта, который может быть более эффективным, чем класс для типов с небольшим объемом данных и простым поведением.

Синтаксис

[ 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>] . Дополнительные сведения см. в каждой статье.

См. также