Compartir a través de


Campos explícitos: palabra clave val (F#)

La palabra clave val se utiliza para declarar un campo en un tipo de clase o estructura sin inicializarlo. Los campos declarados de esta manera se denominan campos explícitos.

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

Comentarios

Los campos en un tipo de clase o estructura suelen definirse mediante un enlace let. Sin embargo, los enlaces let deben inicializarse como parte del constructor de clase, lo cual no siempre es posible, necesario o deseable. Se puede usar la palabra clave val para campos no inicializados.

Los campos explícitos pueden ser estáticos o no estáticos. access-modifier puede ser public, private o internal. De forma predeterminada, los campos explícitos son públicos. Sin embargo, los enlaces let en las clases siempre son privados.

Se requiere el atributo DefaultValue en los campos explícitos de los tipos de clase que tienen un constructor primario. Este atributo especifica que el campo se inicializa en cero. El tipo del campo debe admitir la inicialización en cero. Un tipo admite la inicialización en cero si es:

  • Un tipo primitivo que tenga un valor cero.

  • Un tipo que admita un valor null como un valor normal, un valor anómalo o una representación de un valor. Esto incluye clases, tuplas, registros, funciones, interfaces, tipos de referencia de .NET, el tipo unit y los tipos de unión discriminada.

  • Un tipo de valor de .NET.

  • Una estructura cuyos campos admitan el valor cero como valor predeterminado.

En el código siguiente, se muestra el uso de campos explícitos y, para poder realizar una comparación, se muestra un enlace let en una clase que tiene un constructor primario. Observe que el campo enlazado mediante let, myInt1, es privado. Cuando se hace referencia al campo enlazado mediante let, myInt1, desde un método miembro, no se requiere el identificador de instancia actual this. Sin embargo, cuando se hace referencia a los campos explícitos myInt2 y myString, se requiere el identificador de instancia actual.

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)

La salida es la siguiente:

11 12 abc

30 def

En el código siguiente se muestra el uso de campos explícitos en una clase que no tiene un constructor primario. En este caso, no se requiere el atributo DefaultValue, pero todos los campos deben inicializarse en los constructores definidos para el 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)

El resultado es 35 22

En el código siguiente se muestra el uso de campos explícitos en una estructura. Dado que una estructura es un tipo de valor, tiene automáticamente un constructor predeterminado que establece en cero los valores de sus campos. Por consiguiente, no se requiere el atributo DefaultValue.

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)

El resultado es 11 xyz

Los campos explícitos no están pensados para un uso rutinario. En general, siempre que sea posible, debe usarse un enlace let en una clase en lugar de un campo explícito. Los campos explícitos son útiles en determinados escenarios de interoperabilidad, como cuando se necesita definir una estructura que se va a usar en una llamada de invocación de plataforma a una API nativa, o en escenarios de interoperabilidad COM. Para obtener más información, vea Funciones externas (F#). Otro caso en el que podría ser necesario un campo explícito es cuando se usa un generador de código F# que emite clases sin constructor primario. Los campos explícitos también son útiles para las variables estáticas de subprocesos o construcciones similares. Para obtener más información, vea ThreadStaticAttribute.

Vea también

Referencia

Enlaces let en clases (F#)

Conceptos

Miembros (F#)