Partilhar via


Estruturas

Uma estrutura é um tipo de objeto compacto que pode ser mais eficiente do que uma classe para tipos que têm uma pequena quantidade de dados e comportamento simples.

Sintaxe

[ 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

Observações

As estruturas são tipos de valor, o que significa que elas são armazenadas diretamente na pilha ou, quando são usadas como campos ou elementos de matriz, embutidas no tipo pai. Ao contrário de classes e registros, as estruturas têm semântica de passagem por valor. Isso significa que eles são úteis principalmente para pequenos agregados de dados que são acessados e copiados com frequência.

Na sintaxe anterior, duas formas são mostradas. A primeira não é a sintaxe leve, mas é usada com frequência porque, quando você usa as struct palavras-chave e end , pode omitir o StructAttribute atributo, que aparece na segunda forma. Você pode abreviar StructAttribute para apenas Struct.

O tipo-definição-elementos-e-membros na sintaxe anterior representa declarações e definições de membros. As estruturas podem ter construtores e campos mutáveis e imutáveis, e podem declarar membros e implementações de interface. Para obter mais informações, consulte Membros.

As estruturas não podem participar na herança, não podem conter let ou do ligar e não podem conter recursivamente campos do seu próprio tipo (embora possam conter células de referência que fazem referência ao seu próprio tipo).

Como as estruturas não permitem let associações, você deve declarar campos em estruturas usando a val palavra-chave. A val palavra-chave define um campo e seu tipo, mas não permite a inicialização. Em vez disso, val as declarações são inicializadas como zero ou nulo. Por esse motivo, as estruturas que têm um construtor implícito (ou seja, parâmetros que são dados imediatamente após o nome da estrutura na declaração) exigem que val as declarações sejam anotadas com o DefaultValue atributo. As estruturas que têm um construtor definido ainda suportam inicialização zero. Portanto, o DefaultValue atributo é uma declaração de que esse valor zero é válido para o campo. Construtores implícitos para estruturas não executam nenhuma ação porque letdo e ligações não são permitidas no tipo, mas os valores de parâmetros implícitos do construtor passados estão disponíveis como campos privados.

Construtores explícitos podem envolver a inicialização de valores de campo. Quando você tem uma estrutura que tem um construtor explícito, ela ainda suporta inicialização zero; no entanto, você não usa o DefaultValue atributo nas declarações porque ele entra em val conflito com o construtor explícito. Para obter mais informações sobre val declarações, consulte Campos explícitos: a val palavra-chave.

Atributos e modificadores de acessibilidade são permitidos em estruturas e seguem as mesmas regras de outros tipos. Para obter mais informações, consulte Atributos e controle de acesso.

Os exemplos de código a seguir ilustram definições de estrutura.

// 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 estruturas

Você pode definir suas próprias estruturas que podem aderir à byrefsemântica -like: consulte Byrefs para obter mais informações. Isso é feito com o IsByRefLikeAttribute atributo:

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 não implica Struct. Ambos devem estar presentes no tipo.

Uma estrutura "byref-like" em F# é um tipo de valor vinculado a pilha. Ele nunca é alocado na pilha gerenciada. Um byrefstruct -like é útil para programação de alto desempenho, pois é aplicado com um conjunto de verificações fortes sobre o tempo de vida e a não captura. As regras são:

  • Eles podem ser usados como parâmetros de função, parâmetros de método, variáveis locais, retornos de método.
  • Eles não podem ser estáticos ou membros de instância de uma classe ou struct normal.
  • Eles não podem ser capturados por qualquer construção de fechamento (async métodos ou expressões lambda).
  • Eles não podem ser usados como um parâmetro genérico.

Embora essas regras restrinjam muito fortemente o uso, elas o fazem para cumprir a promessa de computação de alto desempenho de maneira segura.

Estruturas ReadOnly

Você pode anotar structs com o IsReadOnlyAttribute atributo. Por exemplo:

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

IsReadOnly não implica Struct. Você deve adicionar ambos para ter uma IsReadOnly estrutura.

O uso desse atributo emite metadados permitindo que F# e C# saibam tratá-lo como inref<'T> e in ref, respectivamente.

Definir um valor mutável dentro de uma struct somente leitura produz um erro.

Estruturar Registros e Sindicatos Discriminados

Você pode representar Registros e Uniões Discriminadas como estruturas com o [<Struct>] atributo. Consulte cada artigo para saber mais.

Consulte também