Freigeben über


Umwandlungen und Konvertierungen (F#)

In diesem Artikel wird die Unterstützung für Typkonvertierungen in F# beschrieben.

Arithmetische Typen

F# stellt Konvertierungsoperatoren für arithmetische Konvertierungen zwischen verschiedenen Grundtypen bereit, z. B. zwischen ganzzahligen und Gleitkommatypen. Die Integral- und Zeichenkonvertierungsoperatoren haben überprüfte und deaktivierte Formulare; die Gleitkommaoperatoren und der Konvertierungsoperator enum nicht. Die deaktivierten Formulare sind in FSharp.Core.Operators definiert, und die überprüften Formulare werden in FSharp.Core.Operators.Checkeddefiniert. Die überprüften Formulare überprüfen auf Überlauf und generieren eine Laufzeitausnahme, wenn der resultierende Wert die Grenzwerte des Zieltyps überschreitet.

Jeder dieser Operatoren hat denselben Namen wie der Name des Zieltyps. Im folgenden Code, in dem die Typen explizit kommentiert werden, byte wird beispielsweise mit zwei unterschiedlichen Bedeutungen angezeigt. Das erste Vorkommen ist der Typ und der zweite der Konvertierungsoperator.

let x : int = 5

let b : byte = byte x

In der folgenden Tabelle sind Konvertierungsoperatoren aufgeführt, die in F# definiert sind.

Bediener BESCHREIBUNG
byte Konvertieren in Byte, ein nicht signierter 8-Bit-Typ.
sbyte In signiertes Byte konvertieren.
int16 Konvertieren sie in eine 16-Bit-ganzzahlige Vorzeichen.
uint16 Konvertieren sie in eine 16-Bit-ganzzahl ohne Vorzeichen.
int32, int Konvertieren in eine 32-Bit-Ganzzahl mit Vorzeichen.
uint32 Konvertieren sie in eine 32-Bit-ganzzahl ohne Vorzeichen.
int64 Konvertieren in eine 64-Bit-Ganzzahl mit Vorzeichen.
uint64 Konvertieren in eine 64-Bit-ganzzahl ohne Vorzeichen.
nativeint Konvertieren in eine systemeigene ganze Zahl.
unativeint Konvertieren in eine nicht signierte systemeigene ganze Zahl.
float, double Konvertieren Sie in eine 64-Bit-Ieee-Gleitkommazahl mit doppelter Genauigkeit.
float32, single Konvertieren Sie eine 32-Bit-Ieee-Gleitkommazahl mit einfacher Genauigkeit.
decimal Konvertieren in System.Decimal.
char Konvertieren in System.Char, ein Unicode-Zeichen.
enum Konvertieren in einen Aufzählungstyp.

Zusätzlich zu integrierten Grundtyptypen können Sie diese Operatoren mit Typen verwenden, die mit entsprechenden Signaturen implementiert op_Explicit oder Methoden implementiert werden op_Implicit . Der Konvertierungsoperator funktioniert z. B. mit jedem Typ, der int eine statische Methode op_Explicit bereitstellt, die den Typ als Parameter verwendet und zurückgibt int. Als besondere Ausnahme der allgemeinen Regel, die Methoden nicht durch Rückgabetyp überladen werden können, können Sie dies für op_Explicit und op_Implicit.

Aufzählungstypen

Der enum Operator ist ein generischer Operator, der einen Typparameter verwendet, der den Typ des enum zu konvertierenden Parameters darstellt. Wenn sie in einen Aufzählungstyp konvertiert wird, versucht die Typinferenz, den Typ des enum Typs zu bestimmen, in den Sie konvertieren möchten. Im folgenden Beispiel wird die Variable col1 nicht explizit kommentiert, aber der Typ wird vom späteren Gleichheitstest abgeleitet. Daher kann der Compiler ableiten, dass Sie in eine Color Enumeration konvertieren. Alternativ können Sie wie im folgenden Beispiel eine Typanmerkung col2 angeben.

type Color =
    | Red = 1
    | Green = 2
    | Blue = 3

// The target type of the conversion cannot be determined by type inference, so the type parameter must be explicit.
let col1 = enum<Color> 1

// The target type is supplied by a type annotation.
let col2 : Color = enum 2

Sie können den Zielenumerationstyp auch explizit als Typparameter angeben, wie im folgenden Code dargestellt:

let col3 = enum<Color> 3

Beachten Sie, dass die Enumeration nur funktioniert, wenn der zugrunde liegende Typ der Enumeration mit dem typ kompatibel ist, der konvertiert wird. Im folgenden Code kann die Konvertierung aufgrund der Fehlenden Übereinstimmung zwischen int32 und uint32.

// Error: types are incompatible
let col4 : Color = enum 2u

Weitere Informationen finden Sie unter Enumerationen.

Umwandlungsobjekttypen

Die Konvertierung zwischen Typen in einer Objekthierarchie ist grundlegend für die objektorientierte Programmierung. Es gibt zwei grundlegende Arten von Konvertierungen: Umwandlung nach oben (Upcasting) und Umwandlung nach unten (Downcasting). Umwandlung einer Hierarchie bedeutet, dass ein Umwandlung von einem abgeleiteten Objektverweis auf einen Basisobjektverweis erfolgt. Eine solche Umwandlung ist garantiert funktionsfähig, solange sich die Basisklasse in der Vererbungshierarchie der abgeleiteten Klasse befindet. Das Umwandeln einer Hierarchie von einem Basisobjektverweis auf einen abgeleiteten Objektverweis ist nur dann erfolgreich, wenn es sich bei dem Objekt tatsächlich um eine Instanz des richtigen Zieltyps (abgeleitet) oder um einen vom Zieltyp abgeleiteten Typ handelt.

F# stellt Operatoren für diese Arten von Konvertierungen bereit. Der :> Operator wandelt die Hierarchie hoch, und der :?> Operator wandelt die Hierarchie herab.

Umwandlung in eine Basisklasse

In vielen objektorientierten Sprachen ist Upcasting implizit; in F# unterscheiden sich die Regeln geringfügig. Upcasting wird automatisch angewendet, wenn Sie Argumente an Methoden für einen Objekttyp übergeben. Für letgebundene Funktionen in einem Modul ist die Upcasting jedoch nicht automatisch, es sei denn, der Parametertyp wird als flexibler Typ deklariert. Weitere Informationen finden Sie unter "Flexible Typen".

Der :> Operator führt eine statische Umwandlung durch, was bedeutet, dass der Erfolg der Umwandlung zur Kompilierungszeit bestimmt wird. Wenn eine Umwandlung, die kompiliert wird, :> erfolgreich kompiliert wird, handelt es sich um eine gültige Umwandlung und hat zur Laufzeit keine Fehlerwahrscheinlichkeit.

Sie können den upcast Operator auch verwenden, um eine solche Konvertierung durchzuführen. Der folgende Ausdruck gibt eine Konvertierung der Hierarchie an:

upcast expression

Wenn Sie den Upcast-Operator verwenden, versucht der Compiler, den Typ abzuleiten, in den Sie konvertieren, aus dem Kontext. Wenn der Compiler den Zieltyp nicht ermitteln kann, meldet der Compiler einen Fehler. Möglicherweise ist eine Typanmerkung erforderlich.

Umwandlung in eine abgeleitete Klasse

Der :?> Operator führt eine dynamische Umwandlung aus, was bedeutet, dass der Erfolg der Umwandlung zur Laufzeit bestimmt wird. Eine Umwandlung, die den :?> Operator verwendet, wird zur Kompilierungszeit nicht überprüft, aber zur Laufzeit wird versucht, in den angegebenen Typ zu umwandeln. Wenn das Objekt mit dem Zieltyp kompatibel ist, wird die Umwandlung erfolgreich ausgeführt. Wenn das Objekt nicht mit dem Zieltyp kompatibel ist, löst die Laufzeit eine InvalidCastException.

Sie können den downcast Operator auch verwenden, um eine dynamische Typkonvertierung durchzuführen. Der folgende Ausdruck gibt eine Konvertierung in eine Hierarchie nach unten in einen Typ an, der aus dem Programmkontext abgeleitet wird:

downcast expression

Wenn der upcast Compiler einen bestimmten Zieltyp nicht aus dem Kontext ableiten kann, meldet er einen Fehler. Möglicherweise ist eine Typanmerkung erforderlich.

Im folgenden Code wird die Verwendung der :> Operatoren veranschaulicht :?> . Der Code veranschaulicht, dass der Operator am besten verwendet wird, wenn Sie wissen, dass die :?> Konvertierung erfolgreich ist, da er ausgelöst wird InvalidCastException , wenn die Konvertierung fehlschlägt. Wenn Sie nicht wissen, dass eine Konvertierung erfolgreich ist, ist ein Typtest, der einen match Ausdruck verwendet, besser, da dadurch der Aufwand beim Generieren einer Ausnahme vermieden wird.

type Base1() =
    abstract member F : unit -> unit
    default u.F() =
     printfn "F Base1"

type Derived1() =
    inherit Base1()
    override u.F() =
      printfn "F Derived1"


let d1 : Derived1 = Derived1()

// Upcast to Base1.
let base1 = d1 :> Base1

// This might throw an exception, unless
// you are sure that base1 is really a Derived1 object, as
// is the case here.
let derived1 = base1 :?> Derived1

// If you cannot be sure that b1 is a Derived1 object,
// use a type test, as follows:
let downcastBase1 (b1 : Base1) =
   match b1 with
   | :? Derived1 as derived1 -> derived1.F()
   | _ -> ()

downcastBase1 base1

Da die generischen Operatoren downcast und upcast die Ableitung vom Typ abhängig sind, um das Argument und den Rückgabetyp zu bestimmen, können Sie im vorherigen Codebeispiel durch let base1: Base1 = upcast d1.let base1 = d1 :> Base1

Eine Typanmerkung ist erforderlich, da upcast die Basisklasse selbst nicht bestimmt werden konnte.

Implizite Upcast-Konvertierungen

Implizite Upcasts werden in den folgenden Situationen eingefügt:

  • Wenn Sie einen Parameter für eine Funktion oder Methode mit einem bekannten benannten Typ bereitstellen. Dies schließt ein, wenn ein Konstrukt wie Berechnungsausdrücke oder Slicing zu einem Methodenaufruf wird.

  • Beim Zuweisen oder Stummschalten eines Datensatzfelds oder einer Eigenschaft mit einem bekannten benannten Typ.

  • Wenn eine Verzweigung eines if/then/else Oder match Ausdrucks einen bekannten Zieltyp aufweist, der sich aus einem anderen Verzweigungstyp oder einem allgemeinen bekannten Typ ergibt.

  • Wenn ein Element einer Liste, eines Arrays oder eines Sequenzausdrucks einen bekannten Zieltyp aufweist.

Betrachten Sie z. B. den folgenden Code:

open System
open System.IO

let findInputSource () : TextReader =
    if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
        // On Monday a TextReader
        Console.In
    else
        // On other days a StreamReader
        File.OpenText("path.txt")

Hier werden die Zweige der bedingten Berechnung jeweils berechnet TextReaderStreamReader . In der zweiten Verzweigung stammt TextReader der bekannte Zieltyp aus der Typanmerkung für die Methode und aus der ersten Verzweigung. Dies bedeutet, dass in der zweiten Verzweigung keine Upcast erforderlich ist.

Zum Anzeigen einer Warnung an jedem Punkt, an dem ein zusätzlicher impliziter Upcast verwendet wird, können Sie Warnung 3388 (/warnon:3388 oder Eigenschaft <WarnOn>3388</WarnOn>) aktivieren.

Implizite numerische Konvertierungen

F# verwendet die explizite Erweiterung numerischer Typen in den meisten Fällen über Konvertierungsoperatoren. Beispielsweise ist für die meisten numerischen Typen explizite Verbreiterung erforderlich, z. B. für die meisten numerischen Typen, z int8 . B. von oder int16von float32 zu float64, oder wenn der Quell- oder Zieltyp unbekannt ist.

Die implizite Verbreiterung ist jedoch für 32-Bit-Ganzzahlen zulässig, die in den gleichen Situationen wie implizite Upcasts auf 64-Bit-Ganzzahlen erweitert werden. Betrachten Sie beispielsweise ein typisches API-Shape:

type Tensor(…) =
    static member Create(sizes: seq<int64>) = Tensor(…)

Ganzzahlige Literale für int64 können verwendet werden:

Tensor.Create([100L; 10L; 10L])

Oder ganze Zahlenliterale für int32:

Tensor.Create([int64 100; int64 10; int64 10])

Die Verbreiterung erfolgt automatisch für int32 den int32 Quell- und int32doubleZieltyp bis hin zu int64nativeint, wenn während der Typ-Ableitung bekannt ist. In Fällen wie den vorherigen Beispielen int32 können Literale verwendet werden:

Tensor.Create([100; 10; 10])

Sie können optional auch die Warnung 3389 (/warnon:3389 oder Eigenschaft <WarnOn>3389</WarnOn>) aktivieren, um eine Warnung an jedem Punkt der impliziten numerischen Verbreiterung anzuzeigen.

. Implizite Konvertierungen im NET-Stil

.NET-APIs ermöglichen die Definition statischer op_Implicit Methoden, implizite Konvertierungen zwischen Typen bereitzustellen. Diese werden automatisch im F#-Code angewendet, wenn Argumente an Methoden übergeben werden. Betrachten Sie beispielsweise den folgenden Code, der explizite Aufrufe an op_Implicit Methoden vornimmt:

open System.Xml.Linq

let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")

. Konvertierungen im NET-Stil op_Implicit werden automatisch für Argumentausdrücke angewendet, wenn Typen für Quellausdruck und Zieltyp verfügbar sind:

open System.Xml.Linq

let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants("Item")

Sie können optional auch die Warnung 3395 (/warnon:3395 oder Eigenschaft <WarnOn>3395</WarnOn>) aktivieren, um an jedem Punkt eine Warnung anzuzeigen. Die implizite Konvertierung im NET-Stil wird verwendet.

. Konvertierungen im NET-Stil op_Implicit werden auch automatisch für Ausdrücke angewendet, die keine Methodenargumente sind, in denselben Situationen wie implizite Upcasts. Wenn jedoch häufig oder unangemessen verwendet wird, können implizite Konvertierungen schlecht mit Typableitung interagieren und zu Code führen, der schwieriger zu verstehen ist. Aus diesem Grund generieren diese Warnungen immer, wenn sie in Nicht-Argumentpositionen verwendet werden.

So zeigen Sie an jedem Punkt eine Warnung an, die ein . Die implizite Konvertierung im NET-Stil wird für ein Argument ohne Methode verwendet, Sie können Warnung 3391 (/warnon:3391 oder Eigenschaft <WarnOn>3391</WarnOn>) aktivieren.

Die folgenden optionalen Warnungen werden für die Verwendung impliziter Konvertierungen bereitgestellt:

  • /warnon:3388 (zusätzlicher impliziter Upcast)
  • /warnon:3389 (implizite numerische Erweiterung)
  • /warnon:3391 (op_Implicit standardmäßig bei Nicht-Methodenargumenten aktiviert)
  • /warnon:3395 (op_Implicit bei Methodenargumenten)

Siehe auch