Ottenere una matrice tipizzata da un'unione discriminare di diversi tipi di matrici in F #
-
20-09-2019 - |
Domanda
Se ho un'unione discriminare di diversi tipi di matrici come posso convertire i loro tipi 'reale'?
type ItemStuff =
| Colors of string[]
| Sizes of int[]
let foo = Sizes [|1;2;3|]
Dopo aver eseguito quanto sopra quando ricevo il valore di pippo vedo:
val foo : ItemStuff = Sizes [|1;2;3|]
Come posso ottenere un array reale di int di da pippo? Mi sto solo perdendo un po 'di sintassi che mi permette di accedere a qualcosa di simile
foo.[2]
? Non posso enumerare pippo quindi non ero in grado di utilizzare la mappa. Potrei scrivere un membro per ItemStuff che restituisce una matrice correttamente digitato per ogni diverso tipo di array Sto tornando, ma che proprio non mi sembrava giusto?
Quali sono le mie migliori approcci qui?
Ecco quello che ho finito per fare. tutte le idee su modi migliori per farlo?
type ItemProp =
| Colors of string[]
| Sizes of int[]
| Quants of int[]
member this.GetColors() =
match this with
| Colors (stringArray) ->
stringArray
| _ -> null
member this.GetIntArr() =
match this with
| Sizes (intArray) | Quants (intArray) ->
intArray
|_ -> null
foo.GetIntArr()
Soluzione
Come posso ottenere un array reale di int di da pippo?
Questo è il problema reale in quanto foo
è appena detto di avere tipo ItemStuff
. Quindi è non deve contengono una Sizes
valore a tutti -. Potrebbe essere un Colors
così
Quindi il vostro programma deve decidere qui
let getIntArray = function
| Sizes arr -> arr
| Colors _ -> failwith "Given value doesn't contain an int array`
getIntArray foo
non funzionerà correttamente e getIntArray (Colors [||])
fallirà, ma dal tipo di livello entrambi sono validi.
Si noti che se si è completamente sicuri che l'operazione avrà successo, è possibile utilizzare pattern di corrispondenza direttamente:
let getIntArray (Sizes arr) = arr
Altri suggerimenti
In genere devi usare il pattern matching dal momento che non si sa se un ItemStuff
detiene i colori o taglie. Se è sicuramente sai che hai un esempio Sizes
, si può fare qualcosa di simile:
let (Sizes arr) = foo
per tirare l'array di nuovo fuori.
Se non sono in realtà che rappresenta un o / o scenari (colori o formati), è consigliabile utilizzare un tipo Record qui:
type ItemStuff =
{ Colors : string[];
Sizes : int[] } with
static member Default = { Colors = [||]; Sizes = [||] }
let foo = { ItemStuff.Default with Sizes = [|1;2;3|] }
printfn "%A" foo.Colors // [||]
printfn "%A" foo.Sizes // [|1; 2; 3|]
printfn "%d" foo.Sizes.[2] // 3
È inoltre possibile restituire un tipo di opzione con Nessuno se l'unione discriminati non era un Sizes
.
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
Ma tenere a mente che alla fine in F # una funzione trasforma sempre un tipo di dati in ingresso in un tipo di dati di uscita, o una funzione fa solo un effetto collaterale (stampa qualcosa sullo schermo o l'inserimento di dati in un array).
Quindi, per esempio, se si desidera solo per stampare il Sizes
(o nulla se si tratta di un Colors
) sarà più breve di scrivere una nuova funzione per questo scopo:
let printSizes item =
match item with
| Sizes(i) -> printfn "%A" i
| _ -> ()
invece che:
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
let res = getIntArray foo
(function | Some(i) -> printfn "%A" i | _ -> ()) res