Obtenir un tableau typé d'une union discriminante de différents types de tableaux dans F #

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

  •  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()
Était-ce utile?

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top