Erhalten ein typisierten Array aus einer diskriminieren Vereinigung verschiedenen Typen von Arrays in F #
-
20-09-2019 - |
Frage
Wenn ich eine diskriminieren Vereinigung verschiedenen Typen von Arrays, wie kann ich sie auf ihre ‚tatsächlichen‘ Typen umwandeln?
type ItemStuff =
| Colors of string[]
| Sizes of int[]
let foo = Sizes [|1;2;3|]
Nach dem Ausführen der oben, wenn ich den Wert von foo erhalte ich sehen:
val foo : ItemStuff = Sizes [|1;2;3|]
Wie kann ich eine tatsächliche Array von int bekommen ist von foo? Fehle ich einige Syntax nur die mir wie der Zugang zu etwas erlaubt
foo.[2]
? Ich kann nicht durch foo aufzählen, damit ich nicht in der Lage war Karte zu verwenden. Ich kann ein Mitglied für ItemStuff schreiben, dass kehrt ein richtig getippt Array für jede andere Art von Array Ich kehre, aber das ist einfach nicht richtig schien?
Was sind meine besten hier Ansätze?
Hier ist, was ich tun endete. alle Ideen auf, bessere Möglichkeiten, es zu tun?
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()
Lösung
Wie kann ich eine tatsächliche Array von int der von foo bekommen?
Das ist das eigentliche Problem, da foo
nur sagt, Typ ItemStuff
haben. So ist es hat nicht zu enthalten einen Sizes
-Wert überhaupt -. Es auch ein Colors
sein könnte
Damit Ihr Programm hat hier zu entscheiden,
let getIntArray = function
| Sizes arr -> arr
| Colors _ -> failwith "Given value doesn't contain an int array`
getIntArray foo
funktioniert ordnungsgemäß aber getIntArray (Colors [||])
fehl, aber von Typ-Ebene beide gültig sind.
Beachten Sie, dass, wenn Sie ganz sicher sind, dass der Vorgang erfolgreich sein, können Sie Pattern-Matching direkt verwenden:
let getIntArray (Sizes arr) = arr
Andere Tipps
Normalerweise würden Sie Pattern-Matching verwenden, da Sie nicht wissen, ob ein ItemStuff
Farben oder Größen hält. Wenn Sie auf jeden Fall wissen, dass Sie eine Sizes
Instanz haben, können Sie so etwas wie:
let (Sizes arr) = foo
das Array zurück zu ziehen.
Wenn Sie nicht wirklich repräsentieren ein entweder / oder-Szenario (Farben oder Größen), sollten Sie mit einem SATZART hier:
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
Sie können auch eine Option Typen mit None zurück, wenn die diskriminierte Union keine Sizes
ist.
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
Aber denken Sie daran, dass am Ende in F # eine Funktion wandelt immer einen Eingangsdatentyp in einen Ausgangsdatentyp oder eine Funktion macht nur eine Nebenwirkung (Druck etwas auf dem Bildschirm oder Daten in eine Array einfügen).
So zum Beispiel, wenn Sie nur die Sizes
drucken möchten (oder nichts, wenn es ein Colors
) es wird kürzer sein, um eine neue Funktion zu diesem Zweck zu schreiben:
let printSizes item =
match item with
| Sizes(i) -> printfn "%A" i
| _ -> ()
statt:
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
let res = getIntArray foo
(function | Some(i) -> printfn "%A" i | _ -> ()) res