Statisch aufgelöste Typparameter
Ein statisch aufgelöster Typparameter ist ein Typparameter, der statt zur Laufzeit zur Kompilierzeit durch einen tatsächlichen Typ ersetzt wird.
Syntax
'type-parameter
Bis Version 7.0 von F# musste die folgende Syntax verwendet werden:
^type-parameter
Bemerkungen
In F# gibt es zwei unterschiedliche Arten von Typparametern. Die erste Art ist der standardmäßige generische Typparameter. Sie entsprechen den generischen Typparametern in anderen .NET-Sprachen. Die andere Art wird statisch aufgelöst und kann nur in Inlinefunktionen verwendet werden.
Statisch aufgelöste Typparameter sind hauptsächlich in Verbindung mit Membereinschränkungen nützlich, die Ihnen die Angabe ermöglichen, dass ein Typargument zur Verwendung einen bestimmten Member oder mehrere Member aufweisen muss. Es gibt keine Möglichkeit, diese Art von Einschränkung mit einem regulären generischen Typparameter zu erstellen.
In der folgenden Tabelle werden die Ähnlichkeiten und die Unterschiede zwischen den beiden Arten von Typparametern zusammengefasst.
Feature | Allgemein | Statisch aufgelöst |
---|---|---|
Auflösungszeit | Laufzeit | Kompilierzeit |
Member-Einschränkungen | Kann nicht mit Membereinschränkungen verwendet werden. | Kann mit Membereinschränkungen verwendet werden. |
Codeerzeugung | Ein Typ (oder eine Methode) mit standardmäßigen generischen Typparametern führt zur Erstellung eines einzelnen generischen Typs oder einer Methode. | Mehrere Instanziierungen von Typen und Methoden werden generiert, einer für jeden erforderlichen Typ. |
Verwendung mit Typen | Kann mit Typen verwendet werden. | Kann nicht mit Typen verwendet werden. |
Verwendung mit Inlinefunktionen | Eine Inlinefunktion kann nicht mit einem standardmäßigen generischen Typparameter parametrisiert werden. Wenn die Eingaben nicht vollständig generisch sind, ist der F#-Compiler darauf spezialisiert oder gibt, wenn keine Optionen zur Spezialisierung vorhanden sind, einen Fehler. | Statisch aufgelöste Typparameter können nicht auf Funktionen oder Methoden angewendet werden, die nicht inline sind. |
Viele F#-Kernbibliotheksfunktionen, besonders Operatoren, verfügen über statisch aufgelöste Typparameter. Diese Funktionen und die Operatoren sind inline, und ergeben effiziente Codeerstellung für numerische Berechnungen.
Inlinemethoden und -funktionen, die Operatoren oder andere Funktionen mit statisch aufgelösten Typparametern verwenden, können auch selbst statisch aufgelöste Typparameter verwenden. Oft leitet der Typrückschluss ab, dass solche Inlinefunktionen statisch aufgelöste Typparameter aufweisen. Im folgenden Beispiel wird eine Operatordefinition veranschaulicht, die so abgeleitet wird, dass sie einen statisch aufgelösten Typparameter hat.
let inline (+@) x y = x + x * y
// Call that uses int.
printfn "%d" (1 +@ 1)
// Call that uses float.
printfn "%f" (1.0 +@ 0.5)
Der aufgelöste Typ von (+@)
basiert auf der Verwendung von (+)
und (*)
, durch die vom Typrückschluss Membereinschränkungen für die statisch aufgelösten Typparameter abgeleitet werden. Der aufgelöste Typ, wie im F#-Interpreter angezeigt, lautet wie folgt.
'a -> 'c -> 'd
when ('a or 'b) : (static member ( + ) : 'a * 'b -> 'd) and
('a or 'c) : (static member ( * ) : 'a * 'c -> 'b)
Die Ausgabe lautet wie folgt.
2
1.500000
Im folgenden Beispiel wird die Verwendung von SRTPs mit Methoden und statischen Methoden veranschaulicht:
type Record =
{ Number: int }
member this.Double() = { Number = this.Number * 2 }
static member Zero() = { Number = 0 }
let inline double<'a when 'a:(member Double: unit -> 'a)> (x: 'a) = x.Double()
let inline zero<'a when 'a:(static member Zero: unit -> 'a)> () = 'a.Zero()
let r: Record = zero ()
let doubleR = double r
Ab F# 7.0 können Sie 'a.Zero()
verwenden, anstatt die Einschränkung wie im folgenden Beispiel wiederholen zu müssen.
Ab F# 4.1 können Sie auch konkrete Typnamen in statisch aufgelösten Typparametersignaturen angeben. In früheren Versionen der Sprache wurde der Typname vom Compiler abgeleitet, konnte aber nicht in der Signatur angegeben werden. Seit F# 4.1 können Sie auch konkrete Typnamen in statisch aufgelösten Typparametersignaturen angeben. Hier finden Sie ein Beispiel (beachten Sie, dass in diesem Beispiel weiterhin ^
verwendet werden muss, da die Vereinfachung der Verwendung '
nicht unterstützt wird):
let inline konst x _ = x
type CFunctor() =
static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a
static member inline fmap (f: ^a -> ^b, a: ^a option) =
match a with
| None -> None
| Some x -> Some (f x)
// default implementation of replace
static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) =
((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f))
// call overridden replace if present
static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) =
(^b : (static member replace: ^a * ^b -> ^c) (a, f))
let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) =
((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f))
// Note the concrete type 'CFunctor' specified in the signature
let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) =
replace_instance<CFunctor, _, _, _> (a, f)