Flexibele typen

Een aantekening van een flexibel type geeft aan dat een parameter, variabele of waarde een type heeft dat compatibel is met een opgegeven type, waarbij compatibiliteit wordt bepaald door de positie in een objectgeoriënteerde hiërarchie van klassen of interfaces. Flexibele typen zijn handig wanneer de automatische conversie naar typen hoger in de typehiërarchie niet plaatsvindt, maar u uw functionaliteit toch wilt inschakelen voor gebruik met elk type in de hiërarchie of elk type dat een interface implementeert.

Syntaxis

#type

Opmerkingen

In de vorige syntaxis vertegenwoordigt het type een basistype of een interface.

Een flexibel type is gelijk aan een algemeen type dat een beperking heeft die de toegestane typen beperkt tot typen die compatibel zijn met het basis- of interfacetype. Dat wil gezegd: de volgende twee regels code zijn gelijkwaardig.

#SomeType

'T when 'T :> SomeType

Flexibele typen zijn handig in verschillende soorten situaties. Als u bijvoorbeeld een hogere volgorde hebt (een functie die een functie als argument gebruikt), is het vaak handig om ervoor te zorgen dat de functie een flexibel type retourneert. In het volgende voorbeeld kan het gebruik van een flexibel type met een reeksargument iterate2 de hogere volgordefunctie gebruiken met functies die reeksen, matrices, lijsten en andere opsommingstypen genereren.

Houd rekening met de volgende twee functies, waarvan één een reeks retourneert, waarvan de andere een flexibel type retourneert.

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])

Bekijk als een ander voorbeeld de bibliotheekfunctie Seq.concat :

val concat: sequences:seq<#seq<'T>> -> seq<'T>

U kunt een van de volgende opsommingsreeksen doorgeven aan deze functie:

  • Een lijst met lijsten
  • Een lijst met matrices
  • Een matrix met lijsten
  • Een matrix met reeksen
  • Elke andere combinatie van opsommingsreeksen

In de volgende code wordt gebruikgemaakt Seq.concat van de scenario's die u kunt ondersteunen met behulp van flexibele typen.

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

De uitvoer is als volgt.

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; ...]

In F# zijn er, net als in andere objectgeoriënteerde talen, contexten waarin afgeleide typen of typen die interfaces implementeren, automatisch worden geconverteerd naar een basistype of interfacetype. Deze automatische conversies vinden plaats in directe argumenten, maar niet wanneer het type zich in een onderliggende positie bevindt, als onderdeel van een complexer type, zoals een retourtype van een functietype of als een typeargument. De flexibele type notatie is dus voornamelijk nuttig wanneer het type waarop u deze toepast, deel uitmaakt van een complexer type.

Zie ook