Cast et conversions (F#)
Cette rubrique décrit la prise en charge pour les conversions de type en F#.
Types arithmétiques
F# fournit des opérateurs de conversion pour les conversions arithmétiques entre différents types primitifs, par exemple entre un type entier et un type à virgule flottante.Les opérateurs de conversion d'intégraux et de caractères ont des formes vérifiées (checked) et non vérifiées (unchecked) ; les opérateurs à virgule flottante et l'opérateur de conversion enum n'en ont pas.Les formes non vérifiées (unchecked) sont définies dans Microsoft.FSharp.Core.Operators, et les formes vérifiées (checked) dans Microsoft.FSharp.Core.Operators.Checked.Les formes vérifiées (checked) vérifient le dépassement de capacité et génèrent une exception runtime si la valeur résultante dépasse les limites du type cible.
Chacun de ces opérateurs a le même nom que le nom du type de destination.Par exemple, dans le code suivant où les types sont annotés explicitement, byte apparaît avec deux significations différentes.La première occurrence est le type et la seconde est l'opérateur de conversion.
let x : int = 5
let b : byte = byte x
Le tableau suivant affiche les opérateurs de conversion définis en F#.
Opérateur |
Description |
---|---|
byte |
Convertit en octet, un type non signé 8 bits. |
sbyte |
Convertit en octet signé. |
int16 |
Convertit en entier signé 16 bits. |
uint16 |
Convertit en entier non signé 16 bits. |
int32, int |
Convertit en entier signé 32 bits. |
uint32 |
Convertit en entier non signé 32 bits. |
int64 |
Convertit en entier signé 64 bits. |
uint64 |
Convertit en entier non signé 64 bits. |
nativeint |
Convertit en entier natif. |
unativeint |
Convertit en entier natif non signé. |
float, double |
Convertit en nombre à virgule flottante IEEE double précision 64 bits. |
float32, single |
Convertit en nombre à virgule flottante IEEE simple précision 32 bits. |
decimal |
Convertit en System.Decimal. |
char |
Convertit en System.Char, un caractère Unicode. |
enum |
Convertit en type énuméré. |
En plus des types primitifs intégrés, vous pouvez utiliser ces opérateurs avec les types qui implémentent les méthodes op_Explicit ou op_Implicit avec les signatures appropriées.Par exemple, l'opérateur de conversion int fonctionne avec tout type qui fournit une méthode statique op_Explicit qui prend le type comme un paramètre et retourne int.Comme une exception spéciale à la règle générale qui veut que des méthodes ne peuvent pas être surchargées par le type de retour, vous pouvez procéder ainsi pour op_Explicit et op_Implicit.
Types énumérés
L'opérateur enum est un opérateur générique qui prend un paramètre de type représentant le type d'enum vers lequel effectuer la conversion.Lors de la conversion en type énuméré, l'inférence de type tente de déterminer le type d'enum vers lequel effectuer la conversion.Dans l'exemple suivant, la variable col1 n'est pas annotée explicitement, mais son type est déduit du test d'égalité ultérieur.Par conséquent, le compilateur peut déduire que vous effectuez une conversion vers une énumération Color.Vous pouvez également fournir une annotation de type, comme avec col2 dans l'exemple suivant.
type Color =
| Red = 1
| Green = 2
| Blue = 3
// The target type of the conversion is determined by type inference.
let col1 = enum 1
// The target type is supplied by a type annotation.
let col2 : Color = enum 2
do
if (col1 = Color.Red) then
printfn "Red"
Vous pouvez également spécifier le type d'énumération cible explicitement comme paramètre de type, comme dans le code suivant :
let col3 = enum<Color> 3
Notez que les casts d'énumération fonctionnent uniquement si le type sous-jacent de l'énumération est compatible avec le type en cours de convertion.Dans le code suivant, la conversion ne compile pas en raison de l'incompatibilité entre int32 et uint32.
// Error: types are incompatible
let col4 : Color = enum 2u
Pour plus d’informations, consultez Énumérations (F#).
Cast de types d'objet
La conversion entre types dans une hiérarchie d'objets est un élément fondamental de la programmation orientée objet.Il existe deux types de bases de conversions : le cast ascendant (« upcasting ») et le cast descendant (« downcasting »).Effectuer un cast ascendant dans une hiérarchie signifie effectuer un cast d'une référence d'objet dérivé vers une référence d'objet de base.Le fonctionnement d'un tel cast est garanti tant que la classe de base se trouve dans la hiérarchie d'héritage de la classe dérivée.Un cast descendant dans une hiérarchie, d'une référence d'objet de base vers une référence d'objet dérivé, n'aboutit que si l'objet est réellement une instance du type (dérivé) de destination correct ou un type dérivé du type de destination.
F# fournit des opérateurs pour ces types de conversions.L'opérateur :> effectue un cast ascendant dans la hiérarchie, tandis que l'opérateur :?> effectue un cast descendant dans la hiérarchie.
Cast ascendant
Dans de nombreux langages orientés objet, le cast ascendant est implicite ; en F#, les règles sont légèrement différentes.Le cast ascendant est appliqué automatiquement lorsque vous passez des arguments à des méthodes sur un type d'objet.Toutefois, pour les fonctions liées à let dans un module, le cast ascendant n'est pas automatique, à moins que le type de paramètre ne soit déclaré en tant que type flexible.Pour plus d’informations, consultez Types flexibles (F#).
L'opérateur :> effectue un cast statique, ce qui signifie que la réussite du cast est déterminée au moment de la compilation.Si un cast qui utilise :> se compile correctement, le cast est valide et ne risque pas d'échouer au moment de l'exécution.
Vous pouvez également utiliser l'opérateur upcast pour effectuer une telle conversion.L'expression suivante spécifie une conversion ascendante dans la hiérarchie.
upcast expression
Lorsque vous utilisez l'opérateur upcast, le compilateur tente de déduire le type vers lequel vous effectuez la conversion à partir du contexte.Si le compilateur ne parvient pas à déterminer le type de cible, il signale une erreur.
Cast descendant
L'opérateur :?> effectue un cast dynamique, ce qui signifie que la réussite du cast est déterminée au moment de l'exécution.Un cast qui utilise l'opérateur :?> n'est pas vérifié au moment de la compilation ; mais au moment de l'exécution, une tentative de cast vers le type spécifié est effectuée.Si l'objet est compatible avec le type de cible, le cast aboutit.Si l'objet n'est pas compatible avec le type de cible, le runtime lève InvalidCastException.
Vous pouvez également utiliser l'opérateur downcast pour effectuer une conversion de type dynamique.L'expression suivante spécifie une conversion descendante dans la hiérarchie en un type déduit à partir du contexte du programme.
downcast expression
Comme pour l'opérateur upcast, si le compilateur ne peut pas déduire de type de cible spécifique à partir du contexte, il signale une erreur.
Le code suivant illustre l'utilisation des opérateurs :> et :?>.Le code montre qu'il est préférable d'utiliser l'opérateur :?> lorsque vous savez que la conversion réussira, car il lève InvalidCastException en cas d'échec de la conversion.Si vous n'êtes pas certain de la réussite d'une conversion, il est recommandé d'utiliser un test de type qui utilise une expression match, celui-ci permettant d'éviter la surcharge liée à la génération d'une exception.
type Base1() =
abstract member F : unit -> unit
default u.F() =
printfn "F Base1"
type Derived1() =
inherit Base1()
override u.F() =
printfn "F Derived1"
let d1 : Derived1 = Derived1()
// Upcast to Base1.
let base1 = d1 :> Base1
// This might throw an exception, unless
// you are sure that base1 is really a Derived1 object, as
// is the case here.
let derived1 = base1 :?> Derived1
// If you cannot be sure that b1 is a Derived1 object,
// use a type test, as follows:
let downcastBase1 (b1 : Base1) =
match b1 with
| :? Derived1 as derived1 -> derived1.F()
| _ -> ()
downcastBase1 base1
Étant donné que les opérateurs génériques downcast et upcast reposent sur l'inférence de type pour déterminer l'argument et le type de retour, vous pouvez, dans le code ci-dessus, remplacer
let base1 = d1 :> Base1
par
base1 = upcast d1
Dans le code précédent, le type d'argument et le type de retour sont, respectivement, Derived1 et Base1.
Pour plus d'informations sur les tests de type, consultez Expressions match (F#).