从F#中不同类型数组的区别联合获取类型化数组

时间:2009-12-21 09:32:38

标签: arrays f# discriminated-union

如果我有不同类型数组的区别联合,我怎样才能将它们转换为'实际'类型?

type ItemStuff = 
   | Colors of string[]
   | Sizes of int[]

let foo = Sizes [|1;2;3|]

运行上面的内容后,当我得到foo的值时,我看到了:

val foo : ItemStuff = Sizes [|1;2;3|]

如何从foo获取实际的int数组?我只是缺少一些允许我访问类似的语法 foo.[2]?我不能通过foo枚举所以我无法使用地图。我可以为ItemStuff编写一个成员,为我返回的每个不同类型的数组返回一个正确类型的数组,但那似乎不对吗?

我最好的方法是什么?

这是我最终做的事情。关于更好的方法的任何想法?

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()

4 个答案:

答案 0 :(得分:6)

  

如何从foo获取实际的int数组?

这是实际问题,因为foo只是说ItemStuff类型。因此根本不需要包含Sizes - 值 - 它也可能是Colors

因此你的程序必须在这里决定

let getIntArray = function
    | Sizes arr -> arr
    | Colors _  -> failwith "Given value doesn't contain an int array`

getIntArray foo将正常运行,但getIntArray (Colors [||])将失败,但从类型级别两者都有效。

请注意,如果您完全确定操作会成功,则可以直接使用模式匹配:

let getIntArray (Sizes arr) = arr

答案 1 :(得分:3)

通常你会使用模式匹配,因为你不知道ItemStuff是否包含颜色或大小。如果你肯定知道你有Sizes个实例,你可以这样做:

let (Sizes arr) = foo

将数组拉出来。

答案 2 :(得分:2)

如果您实际上没有表示任何一个/或场景(颜色或大小),请考虑在此处使用Record type

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

答案 3 :(得分:1)

如果受歧视的联合不是Sizes,您也可以返回带有“无”的选项类型。

let getIntArray item =
    match item with
    | Sizes(i) -> Some(i)
    | _        -> None

但请记住,在F#的最后,函数总是将输入数据类型转换为输出数据类型,或者函数只会产生副作用(在屏幕上打印某些内容或将数据插入到数组中)。

因此,例如,如果您只想打印Sizes(如果它是Colors则没有任何内容),为此目的编写新函数会更短:

let printSizes item =
    match item with
    | Sizes(i) -> printfn "%A" i
    | _        -> ()

而不是:

let getIntArray item =
    match item with
    | Sizes(i) -> Some(i)
    | _        -> None

let res = getIntArray foo

(function | Some(i) -> printfn "%A" i | _ -> ()) res