Rugalmas típusok
A rugalmas típusú széljegyzetek azt jelzik, hogy egy paraméter, változó vagy érték egy adott típussal kompatibilis típussal rendelkezik, ahol a kompatibilitást az osztályok vagy interfészek objektumorientált hierarchiájában elfoglalt pozíció határozza meg. A rugalmas típusok akkor hasznosak, ha a típushierarchia magasabb típusaira való automatikus átalakítás nem történik meg, de továbbra is engedélyezni szeretné, hogy a funkció bármilyen típussal működjön a hierarchiában, vagy bármilyen olyan típussal, amely egy felületet implementál.
Syntax
#type
Megjegyzések
Az előző szintaxisban a típus egy alaptípust vagy interfészt jelöl.
A rugalmas típus egyenértékű egy olyan általános típussal, amely olyan korlátozással rendelkezik, amely az engedélyezett típusokat olyan típusokra korlátozza, amelyek kompatibilisek az alap- vagy interfésztípussal. Vagyis a következő két kódsor egyenértékű.
#SomeType
'T when 'T :> SomeType
A rugalmas típusok számos helyzetben hasznosak. Ha például magasabb rendű függvénye van (egy függvény argumentumként egy függvényt vesz fel), gyakran hasznos, ha a függvény rugalmas típust ad vissza. Az alábbi példában iterate2
egy rugalmas típus és egy sorrend argumentum használata lehetővé teszi, hogy a magasabb sorrendű függvény olyan függvényekkel működjön, amelyek sorozatokat, tömböket, listákat és bármilyen más számba írható típust hoznak létre.
Vegye figyelembe a következő két függvényt, amelyek közül az egyik egy sorozatot ad vissza, a másik pedig rugalmas típust ad vissza.
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])
Egy másik példaként tekintse meg a Seq.concat könyvtárfüggvényt :
val concat: sequences:seq<#seq<'T>> -> seq<'T>
Az alábbi számbavételi sorozatok bármelyikét átadhatja ennek a függvénynek:
- Listák listája
- Tömbök listája
- Listák tömbje
- Sorozatok tömbje
- A számbavételi sorozatok bármely más kombinációja
Az alábbi kód a rugalmas típusok használatával támogatott forgatókönyvek bemutatására szolgál Seq.concat
.
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
A kimenet a következő.
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; ...]
Az F#-ban, mint más objektumorientált nyelvekben, vannak olyan környezetek, amelyekben az interfészeket megvalósító származtatott típusok vagy típusok automatikusan alaptípussá vagy felülettípussá alakulnak. Ezek az automatikus átalakítások közvetlen argumentumokban történnek, de nem akkor, ha a típus alárendelt pozícióban van, egy összetettebb típus részeként, például egy függvénytípus visszatérési típusaként vagy típusargumentumként. Így a rugalmas típus jelölése elsősorban akkor hasznos, ha az alkalmazott típus egy összetettebb típus része.