Champs explicites : mot clé val

Le mot clé val est utilisé pour déclarer un emplacement pour stocker une valeur dans un type de classe ou de structure sans l'initialiser. Les emplacements de stockage déclarés de cette manière sont appelés champs explicites. Une autre utilisation du mot clé val consiste à l'associer avec le mot clé member pour déclarer une propriété implémentée automatiquement. Pour plus d’informations sur les propriétés implémentées automatiquement, consultez Propriétés.

Syntaxe

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

Notes

La façon habituelle de définir des champs dans un type de classe ou de structure consiste à utiliser une liaison let. Toutefois, les liaisons let doivent être initialisées dans le cadre du constructeur de classe, ce qui n'est pas toujours possible, nécessaire ou souhaitable. Vous pouvez utiliser le mot clé val quand vous voulez un champ qui n'est pas initialisé.

Les champs explicites peuvent être statiques ou non statiques. access-modifier peut être public, private ou internal. Par défaut, les champs explicites sont publics. À la différence des liaisons let dans les classes, qui elles sont toujours privées.

L’attribut DefaultValue est obligatoire pour les champs explicites dans les types de classe qui ont un constructeur principal. Cet attribut spécifie que le champ est initialisé à zéro. Le type du champ doit prendre en charge l'initialisation à zéro. Un type prend en charge l'initialisation à zéro s'il s'agit d'un type suivant :

  • Type primitif qui a une valeur zéro.
  • Type qui prend en charge une valeur null, en tant que valeur normale, en tant que valeur anormale ou en tant que représentation d'une valeur. Sont inclus les classes, les tuples, les enregistrements, les fonctions, les interfaces, les types référence .NET, le type unit et les types union discriminée.
  • Type valeur .NET.
  • Structure dont les champs prennent tous en charge une valeur zéro par défaut.

Par exemple, un champ immuable appelé someField a un champ de stockage dans la représentation compilée .NET portant le nom someField@ et vous accédez à la valeur stockée à l'aide d'une propriété nommée someField.

Pour un champ mutable, la représentation compilée .NET est un champ .NET.

Avertissement

L’espace de noms .NET Framework System.ComponentModel contient un attribut qui porte le même nom. Pour plus d'informations sur cet attribut, consultez DefaultValueAttribute.

Le code suivant illustre l'utilisation de champs explicites et, à titre de comparaison, d'une liaison let dans une classe qui a un constructeur principal. Notez que le champ lié à letmyInt1 est privé. Quand le champ lié à letmyInt1 est référencé à partir d'une méthode membre, l'auto-identificateur this n'est pas requis. Mais quand vous référencez les champs explicites myInt2 et myString, l'auto-identificateur est requis.

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 sortie se présente comme suit :

11 12 abc
30 def

Le code suivant illustre l'utilisation de champs explicites dans une classe qui n'a pas de constructeur principal. Dans ce cas, l'attribut DefaultValue n'est pas requis, mais tous les champs doivent être initialisés dans les constructeurs définis pour le type.

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)

La sortie est 35 22.

Le code suivant illustre l'utilisation de champs explicites dans une structure. Dans la mesure où une structure est un type valeur, elle a automatiquement un constructeur sans paramètre qui définit les valeurs de ses champs à zéro. Ainsi, l'attribut DefaultValue n'est pas requis.

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)

La sortie est 11 xyz.

Attention, si vous comptez initialiser votre structure avec des champs mutable sans le mot clé mutable, vos affectations fonctionneront sur une copie de la structure, qui sera abandonnée juste après l’affectation. Votre structure ne va donc pas changer.

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

Les champs explicites n'ont pas vocation à être utilisés dans le cadre d'une routine. En général, quand cela est possible, vous devez utiliser une liaison let dans une classe au lieu d’un champ explicite. Les champs explicites s'avèrent utiles dans certains scénarios d'interopérabilité, notamment quand vous devez définir une structure qui sera utilisée dans un appel de code non managé à une API native ou dans des scénarios COM interop. Pour plus d’informations, consultez Fonctions externes. Une autre situation dans laquelle un champ explicite peut s'avérer nécessaire est liée à l'utilisation d'un générateur de code F# qui émet des classes sans constructeur principal. Les champs explicites s'avèrent également utiles pour les variables static de thread ou les constructions similaires. Pour plus d’informations, consultez System.ThreadStaticAttribute.

Quand les mots clés member val apparaissent ensemble dans une définition de type, il s'agit de la définition d'une propriété implémentée automatiquement. Pour plus d'informations, consultez Propriétés.

Voir aussi