Flexible Typen (F#)
Eine flexible Typanmerkung gibt an, dass der Typ eines Parameters, einer Variablen oder eines Werts mit einem angegebenen Typ kompatibel ist, wobei Kompatibilität nach der Position in einer objektorientierten Hierarchie von Klassen oder Schnittstellen bestimmt wird. Flexible Typen sind insbesondere hilfreich, wenn keine automatische Konvertierung in Typen auf einer höheren Ebene der Hierarchie erfolgt und die Funktionalität dennoch für jeden Typ in der Hierarchie oder jeden Typ, der eine Schnittstelle implementiert, verwendet werden können soll.
#type
Hinweise
In der vorherigen Syntax stellt type einen Basistyp oder eine Schnittstelle dar.
Ein flexibler Typ entspricht einem generischen Typ, wobei nur mit dem Basis- oder Schnittstellentyp kompatible Typen zulässig sind. Daher sind die folgenden beiden Codezeilen gleichwertig.
#SomeType
'a when 'a :> SomeType
Flexible Typen sind in verschiedenen Arten von Situationen hilfreich. Beispielsweise ist es bei einer Funktion höherer Ordnung (eine Funktion, die eine Funktion als Argument akzeptiert) häufig sinnvoll, wenn die Funktion einen flexiblen Typ zurückgibt. Im folgenden Beispiel ermöglicht die Verwendung eines flexiblen Typs mit einem Sequenzargument in iterate2, dass die Funktion höherer Ordnung mit Funktionen verwendet werden kann, die Sequenzen, Arrays, Listen und beliebige andere aufzählbare Typen generieren.
Betrachten Sie die folgenden beiden Funktionen, von denen die eine eine Sequenz und die andere einen flexiblen Typ zurückgibt.
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])
Betrachten Sie als weiteres Beispiel die Seq.concat-Bibliotheksfunktion:
val concat: sequences:seq<#seq<'T>> -> seq<'T>
Sie können an diese Funktion jede der folgenden aufzählbaren Sequenzen übergeben:
Eine Liste mit Listen
Eine Liste mit Arrays
Ein Array von Listen
Ein Array von Sequenzen
Eine beliebige andere Kombination aufzählbarer Sequenzen
Im folgenden Code werden mit Seq.concat die Szenarien veranschaulicht, die Sie mithilfe flexibler Typen unterstützen können.
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
Die Ausgabe lautet wie folgt.
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# gibt es wie in anderen objektorientierten Sprachen Kontexte, in denen abgeleitete Typen oder Typen, die Schnittstellen implementieren, automatisch in einen Basistyp oder Schnittstellentyp konvertiert werden. Diese automatischen Konvertierungen erfolgen in direkten Argumenten, jedoch nicht, wenn es sich um einen untergeordneten Typ handelt, der Teil eines komplexeren Typs ist, z. B. ein Rückgabetyp eines Funktionstyps oder ein Funktionsargument. Daher ist die flexible Typanmerkung vor allem hilfreich, wenn der Typ, auf den Sie sie anwenden, Teil eines komplexeren Typs ist.