Compartilhar via


Campos explícitos: a palavra-chave val

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

Sintaxe

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

Comentários

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

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

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

  • Um tipo primitivo que tem um valor zero.
  • Um tipo que dá suporte a um valor nulo, seja 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 do .NET, o tipo unit e tipos de união discriminados.
  • Um tipo de valor do .NET.
  • Uma estrutura cujos campos dão suporte a 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 do .NET.

Aviso

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

O código a seguir mostra o uso de campos explícitos e, para comparação, uma associação let em uma classe que tem um construtor primário. Observe que o campo myInt1 associado ao let é privado. Quando o campo myInt1 associado ao let é referenciado de um método membro, o auto-identificador this não é necessário. Mas quando você está fazendo referência aos campos explícitos myInt2 e myString, o auto-identificador é 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)

A saída é da seguinte maneira:

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 atributo DefaultValue não é necessá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)

A saída é 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 atributo DefaultValue 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)

A saída é 11 xyz.

Cuidado, se você vai inicializar sua estrutura com campos mutable sem a palavra-chave mutable, 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 será alterada.

[<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

Campos explícitos não se destinam ao uso rotineiro. Em geral, quando possível, você deve usar uma associação let em uma classe em vez de um campo explícito. 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 saber mais, 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 constructos semelhantes. Para obter mais informações, consulte System.ThreadStaticAttribute.

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

Confira também