Ottenere una matrice tipizzata da un'unione discriminare di diversi tipi di matrici in F #

StackOverflow https://stackoverflow.com/questions/1939113

  •  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()
È stato utile?

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top