Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Une annotation de type flexible indique qu’un paramètre, une variable ou une valeur a un type compatible avec un type spécifié, où la compatibilité est déterminée par position dans une hiérarchie orientée objet de classes ou d’interfaces. Les types flexibles sont utiles spécifiquement lorsque la conversion automatique en types plus haut dans la hiérarchie de types ne se produit pas, mais que vous souhaitez toujours permettre à vos fonctionnalités d’utiliser n’importe quel type dans la hiérarchie ou tout type qui implémente une interface.
Syntaxe
#type
Remarques
Dans la syntaxe précédente, le type représente un type de base ou une interface.
Un type flexible équivaut à un type générique qui a une contrainte qui limite les types autorisés aux types compatibles avec le type de base ou d’interface. Autrement dit, les deux lignes de code suivantes sont équivalentes.
#SomeType
'T when 'T :> SomeType
Les types flexibles sont utiles dans plusieurs types de situations. Par exemple, lorsque vous disposez d’une fonction d’ordre supérieur (fonction qui prend une fonction en tant qu’argument), il est souvent utile de faire en sorte que la fonction retourne un type flexible. Dans l’exemple suivant, l’utilisation d’un type flexible avec un argument iterate2 de séquence permet à la fonction d’ordre supérieur d’utiliser des fonctions qui génèrent des séquences, des tableaux, des listes et tout autre type énumérable.
Considérez les deux fonctions suivantes, dont l’une retourne une séquence, l’autre qui retourne un type flexible.
let iterate1 (f : unit -> seq<int>) =
for e in f() do printfn "%d" e
let iterate2 (f : unit -> #seq<int>) =
for e in f() do printfn "%d" e
// Passing a function that takes a list requires a cast.
iterate1 (fun () -> [1] :> seq<int>)
// Passing a function that takes a list to the version that specifies a
// flexible type as the return value is OK as is.
iterate2 (fun () -> [1])
Comme autre exemple, considérez la fonction de bibliothèque Seq.concat :
val concat: sequences:seq<#seq<'T>> -> seq<'T>
Vous pouvez passer l’une des séquences énumérables suivantes à cette fonction :
- Liste des listes
- Liste des tableaux
- Tableau de listes
- Tableau de séquences
- Toute autre combinaison de séquences énumérables
Le code suivant utilise Seq.concat pour illustrer les scénarios que vous pouvez prendre en charge à l’aide de types flexibles.
let list1 = [1;2;3]
let list2 = [4;5;6]
let list3 = [7;8;9]
let concat1 = Seq.concat [ list1; list2; list3]
printfn "%A" concat1
let array1 = [|1;2;3|]
let array2 = [|4;5;6|]
let array3 = [|7;8;9|]
let concat2 = Seq.concat [ array1; array2; array3 ]
printfn "%A" concat2
let concat3 = Seq.concat [| list1; list2; list3 |]
printfn "%A" concat3
let concat4 = Seq.concat [| array1; array2; array3 |]
printfn "%A" concat4
let seq1 = { 1 .. 3 }
let seq2 = { 4 .. 6 }
let seq3 = { 7 .. 9 }
let concat5 = Seq.concat [| seq1; seq2; seq3 |]
printfn "%A" concat5
La sortie est la suivante.
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
Dans F#, comme dans d’autres langages orientés objet, il existe des contextes dans lesquels les types ou types dérivés qui implémentent des interfaces sont automatiquement convertis en type de base ou type d’interface. Ces conversions automatiques se produisent dans des arguments directs, mais pas lorsque le type est dans une position subordonnée, dans le cadre d’un type plus complexe tel qu’un type de retour d’un type de fonction ou comme argument de type. Par conséquent, la notation de type flexible est principalement utile lorsque le type auquel vous l’appliquez fait partie d’un type plus complexe.