Megosztás a következőn keresztül:


Öntés és átalakítás (F#)

Ez a cikk az F#-beli típuskonverziók támogatását ismerteti.

Számtani típusok

Az F# különböző primitív típusok, például egész és lebegőpontos típusok közötti aritmetikai konverziókhoz biztosít konverziós operátorokat. Az integrál- és karakterátalakítás operátorai ellenőrizték és nem ellenőrizték az űrlapokat; a lebegőpontos operátorok és az enum átalakítási operátorok nem. A nem bejelölt űrlapok definiálva vannak, FSharp.Core.Operators az ellenőrzött űrlapok pedig a következőben vannak definiálva FSharp.Core.Operators.Checked: . Az ellenőrzött űrlapok ellenőrzik a túlcsordulást, és futásidejű kivételt hoznak létre, ha az eredmény meghaladja a céltípus korlátait.

Mindegyik operátor neve megegyezik a céltípus nevével. Például a következő kódban, amelyben a típusok kifejezetten jegyzetekkel vannak elkönyvelve, byte két különböző jelentéssel jelenik meg. Az első előfordulás a típus, a második pedig az átalakítás operátora.

let x : int = 5

let b : byte = byte x

Az alábbi táblázat az F#-ban definiált konverziós operátorokat mutatja be.

Operátor Leírás
byte Konvertálás bájtra, amely egy 8 bites, aláíratlan típus.
sbyte Konvertálás aláírt bájttá.
int16 Konvertálás 16 bites aláírt egész számmá.
uint16 Konvertálás 16 bites aláíratlan egész számmá.
int32, int Konvertálás 32 bites aláírt egész számmá.
uint32 Konvertálás 32 bites, aláíratlan egész számmá.
int64 Konvertálás 64 bites aláírt egész számmá.
uint64 Konvertálás 64 bites aláíratlan egész számmá.
nativeint Konvertálás natív egész számmá.
unativeint Konvertálás aláíratlan natív egész számmá.
float, double Konvertálás 64 bites dupla pontosságú I Enterprise kiadás E lebegőpontos számmá.
float32, single Konvertálás 32 bites egypontos I Enterprise kiadás E lebegőpontos számmá.
decimal Konvertálás .System.Decimal
char Konvertálás Unicode-karakterre System.Char.
enum Konvertálás számbavételes típusra.

A beépített primitív típusok mellett ezeket az operátorokat olyan típusokkal is használhatja, amelyek implementálják op_Explicit vagy op_Implicit megfelelő aláírással rendelkező metódusokat használnak. A konvertálási int operátor például bármely olyan típussal működik, amely statikus metódust op_Explicit biztosít, amely paraméterként veszi fel a típust, és visszaadja intazt. Az általános szabály különleges kivétele, hogy a metódusok nem terhelhetők túl a visszatérési típussal, ezt megteheti a következőhöz op_Explicit : és op_Implicit.

Számbavételi típusok

Az enum operátor egy általános operátor, amely egy olyan típusparamétert vesz igénybe, amely a konvertálandó típust enum jelöli. Ha számbavételes típussá alakul át, a típuskövetkeztetés megkísérli meghatározni a konvertálni kívánt típust enum . Az alábbi példában a változó col1 nem explicit módon van széljegyzetekkel eljegyzve, de a típus a későbbi egyenlőségi tesztből következik. Ezért a fordító arra következtethet, hogy enumerálássá konvertálja azokat Color . Másik lehetőségként megadhat egy típusjegyzetet is, ahogyan col2 az alábbi példában is látható.

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

A cél enumerálási típust explicit módon típusparaméterként is megadhatja, ahogyan az alábbi kódban is látható:

let col3 = enum<Color> 3

Vegye figyelembe, hogy az enumerálási leadások csak akkor működnek, ha az enumerálás mögöttes típusa kompatibilis a konvertált típussal. Az alábbi kódban a konvertálás nem fordít le, mert a kettő és uint32a kettő nem int32 egyezik.

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

További információ: Enumerációk.

Objektumtípusok kiosztása

Az objektumhierarchiában lévő típusok közötti átalakítás alapvető fontosságú az objektumorientált programozáshoz. A konverzióknak két alapvető típusa van: a fel- és a leszokás (downcasting). A hierarchia felosztása azt jelenti, hogy egy származtatott objektumhivatkozásból egy alapobjektum-hivatkozásra kell válogatni. Az ilyen leadás garantáltan működni fog mindaddig, amíg az alaposztály a származtatott osztály öröklési hierarchiájában van. Ha egy hierarchiát egy alapobjektum-hivatkozásból származtatott objektumhivatkozásra hoz létre, csak akkor sikerül, ha az objektum valójában a megfelelő céltípus (származtatott) vagy a céltípusból származtatott típus példánya.

Az F# operátorokat biztosít az ilyen típusú konverziókhoz. Az :> operátor feldobja a hierarchiát, az :?> operátor pedig lekösse a hierarchiát.

Felcímkésítés

Számos objektumorientált nyelvben a felcímkésítés implicit; az F#-ban a szabályok kissé eltérnek. A rendszer automatikusan alkalmazza a küldést, amikor argumentumokat ad át egy objektumtípus metódusainak. A modul let-bound függvényei esetében azonban a felcímkésítés nem automatikus, kivéve, ha a paramétertípus rugalmas típusként van deklarálva. További információ: Rugalmas típusok.

Az :> operátor statikus öntöttet hajt végre, ami azt jelenti, hogy a leadás sikerességét a fordítási időpont határozza meg. Ha egy sikeres fordítást használó :> szereplőgárda érvényes, és futásidőben nincs esélye a meghibásodásra.

Az operátorral upcast is végrehajthat ilyen átalakítást. A következő kifejezés a hierarchia átalakítását adja meg:

upcast expression

A felcímkézési operátor használatakor a fordító megpróbálja kikövetkeztetni a környezetből konvertált típust. Ha a fordító nem tudja meghatározni a céltípust, a fordító hibát jelez. Szükség lehet típusjegyzetre.

Downcasting

Az :?> operátor dinamikus leadást végez, ami azt jelenti, hogy a leadás sikerességét futásidőben határozzák meg. Az operátort használó leadásokat a rendszer nem ellenőrzi a :?> fordítási időpontban, de futásidőben a rendszer megpróbálja a megadott típusra leadni a műveletet. Ha az objektum kompatibilis a céltípussal, a leadás sikeres lesz. Ha az objektum nem kompatibilis a céltípussal, a futtatókörnyezet létrehoz egy InvalidCastException.

Az operátorral downcast dinamikus típusátalakítást is végrehajthat. A következő kifejezés a hierarchia olyan típusra való konvertálását adja meg, amely a programkörnyezetből következtet:

downcast expression

Ami az upcast operátort jelenti, ha a fordító nem tud egy adott céltípust kikövetkeztetni a környezetből, hibát jelez. Szükség lehet típusjegyzetre.

Az alábbi kód bemutatja az operátorok és :?> az :> operátorok használatát. A kód azt szemlélteti, hogy az :?> operátor akkor használható a legjobban, ha tudja, hogy az átalakítás sikeres lesz, mert akkor fordul elő InvalidCastException , ha az átalakítás sikertelen lesz. Ha nem tudja, hogy az átalakítás sikeres lesz, akkor a kifejezéseket használó match típustesztek jobbak, mert elkerülik a kivétel létrehozásának többletterhelését.

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

Mivel az általános operátorok downcast és upcast a típuskövetkeztetés alapján határozzák meg az argumentumot és a visszatérési típust, az előző kód példájában lecserélheti let base1 = d1 :> Base1 a következőre let base1: Base1 = upcast d1: .

Szükség van egy típusjegyzetre, mert upcast önmagában nem lehetett meghatározni az alaposztályt.

Implicit felkonvertálások

Az implicit felcímkék a következő helyzetekben lesznek beszúrva:

  • Ha paramétert ad meg egy ismert nevű típussal rendelkező függvénynek vagy metódusnak. Ez magában foglalja azt is, ha egy szerkezet, például számítási kifejezések vagy szeletelés metódushívássá válik.

  • Ismert nevű típusú rekordmező vagy tulajdonság hozzárendelésekor vagy mutációjakor.

  • Ha egy if/then/else vagy match több kifejezés ága egy másik ágból vagy általánosan ismert típusból származó ismert céltípussal rendelkezik.

  • Ha egy lista-, tömb- vagy szekvenciakifejezés egy eleme ismert céltípussal rendelkezik.

Vegyük például a következő kódot:

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

Itt a feltételes számítás ágai számítják ki az a TextReader és StreamReader azokat. A második ágon az ismert céltípus TextReader a metódus típusjegyzetéből és az első ágból származik. Ez azt jelenti, hogy a második ágon nincs szükség felhősítésre.

Ha minden ponton további implicit felcímkésítést szeretne megjeleníteni, engedélyezheti a 3388-as figyelmeztetést (/warnon:3388 vagy tulajdonságot <WarnOn>3388</WarnOn>).

Implicit numerikus konverziók

Az F# a numerikus típusok explicit szélesítését használja a legtöbb esetben konverziós operátorok használatával. Például a legtöbb numerikus típushoz explicit szélesítésre van szükség, például int8int16vagy , vagy a float32 forrástól a célig float64, vagy ha a forrás vagy a cél típusa ismeretlen.

Az implicit szélesítés azonban 64 bites egész számokra szélesített 32 bites egész számok esetében engedélyezett, ugyanabban a helyzetben, mint az implicit felcímkék. Vegyük például egy tipikus API-alakzatot:

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

Az int64 egész számkonstansai használhatók:

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

Vagy egész szám literál az int32-hez:

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

A szélesítés automatikusan int32 történik a int64int32int32nativeintforrás és a doublecél típusának a típuskövetkeztetés során történő ismertsége esetén. Így az olyan esetekben, mint az előző példák, int32 konstansok használhatók:

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

Azt is engedélyezheti, hogy a 3389 figyelmeztetés (/warnon:3389 vagy tulajdonság <WarnOn>3389</WarnOn>) minden ponton implicit számszűkítést használjon.

. NET-stílusú implicit konverziók

A .NET API-k lehetővé teszik a statikus metódusok definícióját op_Implicit , hogy implicit konverziót biztosítsanak a típusok között. Ezeket automatikusan alkalmazza az F#-kód, amikor argumentumokat ad át a metódusoknak. Vegyük például a következő kódot, amely explicit hívásokat indít a metódusokra op_Implicit :

open System.Xml.Linq

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

. A NET-stílusú op_Implicit konverziók automatikusan érvénybe lépnek az argumentumkifejezések esetében, ha a forráskifejezéshez és a céltípushoz típusok érhetők el:

open System.Xml.Linq

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

Azt is engedélyezheti, hogy a 3395-ös figyelmeztetés (/warnon:3395 vagy tulajdonság <WarnOn>3395</WarnOn>) figyelmeztetést jelenítsen meg a figyelmeztetés minden pontján. A rendszer NET-stílusú implicit konverziót használ.

. A NET-stílusú op_Implicit konverziók automatikusan alkalmazva lesznek a nem metódusargumentum-kifejezésekre is az implicit felcímkézettekkel azonos helyzetekben. Ha azonban széles körben vagy nem megfelelő módon használják, az implicit konverziók rosszul kommunikálhatnak a típuskövetkeztetéssel, és nehezebben érthető kódhoz vezethetnek. Ezért ezek mindig figyelmeztetéseket generálnak, ha nem argumentum pozíciókban használják őket.

Figyelmeztetés megjelenítése minden olyan ponton, amikor egy . A NET-stílusú implicit konverzió nem metódus argumentumhoz használható, a 3391-as figyelmeztetést (/warnon:3391 vagy tulajdonságot <WarnOn>3391</WarnOn>) engedélyezheti.

Az implicit konverziókhoz a következő opcionális figyelmeztetések érhetők el:

  • /warnon:3388 (további implicit felcímkés)
  • /warnon:3389 (implicit numerikus szélesítés)
  • /warnon:3391 (op_Implicit nem metódusargumentumok esetében alapértelmezés szerint)
  • /warnon:3395 (op_Implicit metódusargumentumokban)

Lásd még