Cast e conversioni (F#)
In questo argomento viene descritto il supporto per la conversione dei tipi in F#.
Tipi aritmetici
F# fornisce operatori di conversione per le conversioni aritmetiche tra diversi tipi primitivi, ad esempio tipi Integer e a virgola mobile. Gli operatori di conversione di valori integrali e caratteri dispongono di forme verificate e non verificate, mentre gli operatori a virgola mobile e l'operatore di conversione enum no. Le forme non verificate sono definite in Microsoft.FSharp.Core.Operators, mentre quelle verificate in Microsoft.FSharp.Core.Operators.Checked. Le forme verificate consentono di controllare se si verifica un overflow e generano un'eccezione in fase di esecuzione se il valore risultante supera i limiti del tipo di destinazione.
Ognuno di questi operatori ha lo stesso nome del tipo di destinazione. Nel codice seguente, in cui i tipi sono annotati in modo esplicito, byte appare, ad esempio, con due significati diversi. La prima occorrenza corrisponde al tipo e la seconda all'operatore di conversione.
let x : int = 5
let b : byte = byte x
Nella tabella seguente vengono mostrati operatori di conversione definiti in F#.
Operatore |
Descrizione |
---|---|
byte |
Conversione in byte, un tipo senza segno a 8 bit. |
sbyte |
Conversione in byte con segno. |
int16 |
Conversione in Signed Integer a 16 bit. |
uint16 |
Conversione in Unsigned Integer a 16 bit. |
int32, int |
Conversione in Signed Integer a 32 bit. |
uint32 |
Conversione in Unsigned Integer a 32 bit. |
int64 |
Conversione in Signed Integer a 64 bit. |
uint64 |
Conversione in Unsigned Integer a 64 bit. |
nativeint |
Conversione in intero nativo. |
unativeint |
Conversione in intero nativo senza segno. |
float, double |
Conversione in un numero a virgola mobile IEEE e precisione doppia a 64 bit. |
float32, single |
Conversione in un numero a virgola mobile IEEE e precisione singola a 32 bit. |
decimal |
Conversione in System.Decimal. |
char |
Conversione in System.Char, un carattere Unicode. |
enum |
Conversione in un tipo enumerato. |
Oltre ai tipi primitivi incorporati, è possibile utilizzare questi operatori con tipi che implementano op_Explicit o i metodi op_Implicit con le firme appropriate. L'operatore di conversione int è ad esempio compatibile con qualsiasi tipo che fornisce un metodo op_Explicit statico che utilizza il tipo come parametro e restituisce int. Come eccezione speciale alla regola generale che prevede che i metodi non possano essere sottoposti a overload in base al tipo restituito, è possibile eseguire questa operazione per op_Explicit e op_Implicit.
Tipi enumerati
L'operatore enum è un operatore generico che accetta un parametro che rappresenta il tipo di elemento enum in cui eseguire la conversione. Quando viene eseguita la conversione in un tipo enumerato, tramite l'inferenza del tipo viene eseguito un tentativo di determinare il tipo di elemento enum in cui si desidera eseguire la conversione. Nell'esempio seguente la variabile col1 non è annotata in modo esplicito, ma il relativo tipo viene derivato dal test di uguaglianza successivo. Il compilatore può pertanto dedurre che si sta eseguendo la conversione in un'enumerazione Color. In alternativa, è possibile fornire un'annotazione del tipo, come nel caso di col2 nell'esempio seguente.
type Color =
| Red = 1
| Green = 2
| Blue = 3
// The target type of the conversion is determined by type inference.
let col1 = enum 1
// The target type is supplied by a type annotation.
let col2 : Color = enum 2
do
if (col1 = Color.Red) then
printfn "Red"
Cast di tipi di oggetti
La conversione tra tipi in una gerarchia di oggetti è fondamentale per la programmazione orientata a oggetti. Vi sono due tipi di base di conversioni: il cast verso l'alto (upcast) e il cast verso il basso (downcast). L'upcast in una gerarchia indica il cast da un riferimento a un oggetto derivato a un riferimento a un oggetto di base. Tale tipo di cast funziona a condizione che la classe di base si trovi nella gerarchia di ereditarietà della classe derivata. Il downcast in una gerarchia, da un riferimento a un oggetto di base a un riferimento a un oggetto derivato, ha esito positivo solo se l'oggetto è effettivamente un'istanza del tipo di destinazione (derivato) corretto o un tipo derivato dal tipo di destinazione.
In F# sono disponibili operatori per questi tipi di conversioni. L'operatore :> consente di eseguire l'upcast nella gerarchia, mentre l'operatore :?> consente di eseguire il downcast.
Upcast
In numerosi linguaggi orientati a oggetti, l'upcast è implicito, mentre in F# le regole sono leggermente diverse. L'upcast viene eseguito automaticamente quando si passano argomenti ai metodi in un tipo di oggetto. Per le funzioni con associazione let in un modulo, tuttavia, l'upcast non è automatico a meno che il tipo di parametro non venga dichiarato come tipo flessibile. Per ulteriori informazioni, vedere Tipi flessibili (F#).
L'operatore :> consente di eseguire un cast statico, che significa che la riuscita del cast viene determinata in fase di compilazione. Se un cast in cui viene utilizzato l'operatore :> viene compilato correttamente, si tratta di un cast valido e non è possibile che si verifichi un errore in fase di esecuzione.
È anche possibile utilizzare l'operatore upcast per eseguire una conversione di questo tipo. Nell'espressione seguente viene specificata una conversione verso l'alto nella gerarchia.
upcast expression
Quando si utilizza l'operatore di upcast, il compilatore tenta di dedurre il tipo che si sta convertendo dal contesto. Se il compilatore non è in grado di determinare il tipo di destinazione, viene segnalato un errore.
Downcast
L'operatore :?> consente di eseguire un cast dinamico, che significa che la riuscita del cast viene determinata in fase di esecuzione. Un cast in cui viene utilizzato l'operatore :?> non viene controllato in fase di compilazione, ma in fase di esecuzione viene effettuato un tentativo di eseguire il cast al tipo specificato. Se l'oggetto è compatibile con il tipo di destinazione, il cast ha esito positivo. Se l'oggetto non è compatibile con il tipo di destinazione, il runtime genera un evento InvalidCastException.
È anche possibile utilizzare l'operatore downcast per eseguire una conversione dinamica del tipo. Nell'espressione seguente viene specificata una conversione verso il basso della gerarchia in un tipo derivato dal contesto del programma.
downcast expression
Come per l'operatore di upcast, se il compilatore non è in grado di dedurre un tipo di destinazione specifico dal contesto, viene segnalato un errore.
Nel codice seguente viene illustrato l'utilizzo degli operatori :> e :?>. Nel codice viene illustrato che è preferibile utilizzare l'operatore :?> quando si sa che la conversione avrà esito positivo, in quanto, in caso di esito negativo, viene generato un evento InvalidCastException. Se non si è certi che una conversione avrà esito positivo, è consigliabile un test del tipo in cui viene utilizzata l'espressione match, in quanto consente di evitare il sovraccarico dovuto alla generazione di un'eccezione.
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
Poiché gli operatori generici downcast e upcast si basano sull'inferenza del tipo per determinare l'argomento e il tipo restituito, nel codice precedente è possibile sostituire
let base1 = d1 :> Base1
con
base1 = upcast d1
Nel codice precedente il tipo di argomento e i tipi restituiti sono, rispettivamente, Derived1 e Base1.
Per ulteriori informazioni sui test del tipo, vedere Espressioni match (F#).
Vedere anche
Altre risorse
Riferimenti per il linguaggio F#
Cronologia delle modifiche
Data |
Cronologia |
Motivo |
---|---|---|
Settembre 2010 |
Aggiunta di informazioni sull'overload di op_Explicit e op_Implicit in base al tipo restituito. |
Miglioramento delle informazioni. |