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 val
mot clé est associée member
au mot clé 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é à let
myInt1
est privé. Quand le champ lié à let
myInt1
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
- Propriétés
- Members (Membres)
- Liaisons
let
dans des classes