Ö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 int
azt. 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 uint32
a 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
vagymatch
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 int8
int16
vagy , 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 int64
int32
int32
nativeint
forrás és a double
cé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.
A konverziókkal kapcsolatos figyelmeztetések összegzése
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)