Partilhar via


Campos explícitos: A palavra-chave val

A val palavra-chave é usada para declarar um local para armazenar um valor em uma classe ou tipo de estrutura, sem inicializá-lo. Os locais de armazenamento declarados dessa maneira são chamados de campos explícitos. Outro uso da val palavra-chave é em conjunto com a member palavra-chave para declarar uma propriedade implementada automaticamente. Para obter mais informações sobre propriedades implementadas automaticamente, consulte Propriedades.

Sintaxe

val [ mutable ] [ access-modifier ] field-name : type-name

Observações

A maneira usual de definir campos em um tipo de classe ou estrutura é usar uma let ligação. No entanto, let as ligações devem ser inicializadas como parte do construtor de classe, o que nem sempre é possível, necessário ou desejável. Você pode usar a val palavra-chave quando quiser um campo não inicializado.

Os campos explícitos podem ser estáticos ou não estáticos. O modificador de acesso pode ser public, privateou internal. Por padrão, os campos explícitos são públicos. Isso difere das let ligações nas classes, que são sempre privadas.

O atributo DefaultValue é necessário em campos explícitos em tipos de classe que têm um construtor primário. Este atributo especifica que o campo é inicializado como zero. O tipo de campo deve suportar inicialização zero. Um tipo suporta inicialização zero se for um dos seguintes:

  • Um tipo primitivo que tem um valor zero.
  • Um tipo que suporta um valor nulo, como um valor normal, como um valor anormal ou como uma representação de um valor. Isso inclui classes, tuplas, registros, funções, interfaces, tipos de referência .NET, o unit tipo e tipos de união discriminados.
  • Um tipo de valor .NET.
  • Uma estrutura cujos campos suportam um valor zero padrão.

Por exemplo, um campo imutável chamado someField tem um campo de suporte na representação compilada do .NET com o nome someField@, e você acessa o valor armazenado usando uma propriedade chamada someField.

Para um campo mutável, a representação compilada do .NET é um campo .NET.

Aviso

O namespace System.ComponentModel do .NET Framework contém um atributo que tem o mesmo nome. Para obter informações sobre esse atributo, consulte DefaultValueAttribute.

O código a seguir mostra o uso de campos explícitos e, para comparação, uma let associação em uma classe que tem um construtor primário. Observe que o letcampo myInt1 -bound é privado. Quando o letcampo -bound é referenciado a partir de um método membro, o autoidentificador this myInt1 não é necessário. Mas quando você está fazendo referência aos campos myInt2 explícitos e myString, o autoidentificador é necessário.

type MyType() =
    let mutable myInt1 = 10
    [<DefaultValue>] val mutable myInt2 : int
    [<DefaultValue>] val mutable myString : string
    member this.SetValsAndPrint( i: int, str: string) =
       myInt1 <- i
       this.myInt2 <- i + 1
       this.myString <- str
       printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)

let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"

printfn "%d %s" (myObject.myInt2) (myObject.myString)

O resultado é o seguinte:

11 12 abc
30 def

O código a seguir mostra o uso de campos explícitos em uma classe que não tem um construtor primário. Nesse caso, o DefaultValue atributo não é obrigatório, mas todos os campos devem ser inicializados nos construtores definidos para o tipo.

type MyClass =
    val a : int
    val b : int
    // The following version of the constructor is an error
    // because b is not initialized.
    // new (a0, b0) = { a = a0; }
    // The following version is acceptable because all fields are initialized.
    new(a0, b0) = { a = a0; b = b0; }

let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)

O resultado é 35 22.

O código a seguir mostra o uso de campos explícitos em uma estrutura. Como uma estrutura é um tipo de valor, ela tem automaticamente um construtor sem parâmetros que define os valores de seus campos como zero. Portanto, o DefaultValue atributo não é necessário.

type MyStruct =
    struct
        val mutable myInt : int
        val mutable myString : string
    end

let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"

printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)

O resultado é 11 xyz.

Cuidado, se você vai inicializar sua estrutura com mutable campos sem mutable palavra-chave, suas atribuições funcionarão em uma cópia da estrutura que será descartada logo após a atribuição. Portanto, sua estrutura não mudará.

[<Struct>]
type Foo =
    val mutable bar: string
    member self.ChangeBar bar = self.bar <- bar
    new (bar) = {bar = bar}

let foo = Foo "1"
foo.ChangeBar "2" //make implicit copy of Foo, changes the copy, discards the copy, foo remains unchanged
printfn "%s" foo.bar //prints 1

let mutable foo' = Foo "1"
foo'.ChangeBar "2" //changes foo'
printfn "%s" foo'.bar //prints 2

Os campos explícitos não se destinam a utilização de rotina. Em geral, quando possível, você deve usar uma let associação em uma classe em vez de um campo explícito. Os campos explícitos são úteis em determinados cenários de interoperabilidade, como quando você precisa definir uma estrutura que será usada em uma chamada de invocação de plataforma para uma API nativa ou em cenários de interoperabilidade COM. Para obter mais informações, consulte Funções externas. Outra situação em que um campo explícito pode ser necessário é quando você está trabalhando com um gerador de código F# que emite classes sem um construtor primário. Campos explícitos também são úteis para variáveis estáticas de thread ou construções semelhantes. Para obter mais informações, veja System.ThreadStaticAttribute.

Quando as palavras-chave member val aparecem juntas em uma definição de tipo, é uma definição de uma propriedade implementada automaticamente. Para obter mais informações, consulte Propriedades.

Consulte também