Obtenir un tableau typé d'une union discriminante de différents types de tableaux dans F #
-
20-09-2019 - |
Question
Si j'ai une union discriminante de différents types de tableaux comment puis-je les convertir à leurs types « réels »?
type ItemStuff =
| Colors of string[]
| Sizes of int[]
let foo = Sizes [|1;2;3|]
Après avoir exécuté ce qui précède quand je reçois la valeur de foo je vois:
val foo : ItemStuff = Sizes [|1;2;3|]
Comment puis-je obtenir un tableau réel de int de foo? Est-ce que je manque juste une syntaxe qui me permet d'accéder à quelque chose comme
foo.[2]
? Je ne peux pas énumérer foo donc je ne pouvais pas utiliser la carte. Je pourrais écrire un membre pour ItemStuff qui retourne un tableau bien typé pour chaque type de tableau que je suis de retour, mais ne semblait pas?
Quels sont ici mes meilleures approches?
Voici ce que je fini par faire. des idées sur les meilleures façons de le faire?
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()
La solution
Comment puis-je obtenir un tableau réel de int de foo?
C'est le problème réel depuis foo
est juste dit avoir le type ItemStuff
. Donc, il ne pas contiennent une valeur Sizes
du tout -. Il pourrait être un Colors
aussi bien
D'où votre programm doit décider ici
let getIntArray = function
| Sizes arr -> arr
| Colors _ -> failwith "Given value doesn't contain an int array`
getIntArray foo
fonctionnera correctement, mais getIntArray (Colors [||])
échouera, mais de niveau de type deux sont valables.
Notez que si vous êtes complètement sûr que l'opération réussisse, vous pouvez utiliser directement motif correspondant:
let getIntArray (Sizes arr) = arr
Autres conseils
En général, vous utiliseriez pattern matching puisque vous ne saurez pas si un ItemStuff
détient des couleurs ou tailles. Si vous savez certainement que vous avez une instance de Sizes
, vous pouvez faire quelque chose comme:
let (Sizes arr) = foo
pour tirer le tableau arrière.
Si vous représentez pas réellement un ou l'autre / ou scénario (couleurs ou tailles), pensez à utiliser un Type d'enregistrement ici:
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
Vous pouvez également retourner un type d'option avec Aucun si le syndicat n'a pas été discriminé un Sizes
.
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
Mais gardez à l'esprit qu'à la fin en F # fonction transforme toujours un type de données d'entrée dans un type de données de sortie, ou une fonction est tout simplement un effet secondaire (impression quelque chose à l'écran ou l'insertion de données dans un tableau).
Ainsi, par exemple, si vous voulez juste imprimer le Sizes
(ou rien si c'est un Colors
) il sera plus court pour écrire une nouvelle fonction à cette fin:
let printSizes item =
match item with
| Sizes(i) -> printfn "%A" i
| _ -> ()
au lieu de:
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
let res = getIntArray foo
(function | Some(i) -> printfn "%A" i | _ -> ()) res