Получение типизированного массива из различающего объединения различных типов массивов в F # - PullRequest
1 голос
/ 21 декабря 2009

Если у меня есть различное объединение различных типов массивов, как я могу преобразовать их в их «реальные» типы?

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

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

После запуска вышеупомянутого, когда я получаю значение foo, я вижу:

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

Как я могу получить фактический массив int из foo? Мне просто не хватает синтаксиса, который позволяет мне получить доступ к чему-то вроде 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 ]

6 голосов
/ 21 декабря 2009

Как я могу получить фактический массив int из foo?

Это реальная проблема, поскольку 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
3 голосов
/ 21 декабря 2009

Обычно вы используете сопоставление с образцом, поскольку вы не будете знать, содержит ли ItemStuff цвета или размеры. Если вы точно знаете, что у вас есть экземпляр Sizes, вы можете сделать что-то вроде:

let (Sizes arr) = foo

чтобы вытащить массив обратно.

2 голосов
/ 21 декабря 2009

Если вы на самом деле не представляете какой-либо из сценариев (цветов или размеров), рассмотрите вариант использования Тип записи здесь:

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
1 голос
/ 21 декабря 2009

Вы также можете вернуть тип опции с помощью None, если дискриминированный союз не был 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...