System.Array [] не совместим с float [] [] в F # - PullRequest
1 голос
/ 27 октября 2011

Мне нужно вызвать функцию, которая принимает System.Array [] в качестве одного параметра в F #. (Функция находится в библиотеке). Мне нужно передать аргумент типа float [] [] [], но компилятор отказывается компилировать. Чтобы повторить проблему, я написал следующий код

let x : float [] [] = Array.init 2 (fun x -> Array.zeroCreate 3)
x :> System.Array;; // This is OK

val x : float [] [] = [|[|0.0; 0.0; 0.0|]; [|0.0; 0.0; 0.0|]|]

> x :> System.Array [];; //Error

  x :> System.Array [];;
  ^^^^^^^^^^^^^^^^^^^^

stdin(14,1): warning FS0059: The type 'System.Array []' does not have any proper subtypes and need not be used as the target of a static coercion

  x :> System.Array [];;
  ^^^^^^^^^^^^^^^^^^^^

stdin(14,1): error FS0193: Type constraint mismatch. The type 
    float [] []    
is not compatible with type
    System.Array []    
The type 'System.Array' does not match the type 'float []'

Как мне решить эту проблему?

Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 27 октября 2011

Возможность обрабатывать 's[] как 't[], когда 's :> 't делает систему типов .NET неработоспособной (и, вероятно, из-за того, что Java делает то же самое). К сожалению, C # следует .NET в разрешении этого.

Поскольку это функция времени выполнения .NET, вы также можете сделать это в F # через бокс и распаковку:

let x : float[][] = Array.init 2 (fun x -> Array.zeroCreate 3)
let x' = (box x) :?> System.Array[]

Это позволяет избежать накладных расходов при отображении каждого элемента, как в решении Рамона.

Чтобы понять, почему это делает систему типов .NET неработоспособной, рассмотрим следующее:

x'.[0] <- upcast [| "test" |] // System.ArrayTypeMismatchException

Несмотря на то, что мы храним значение типа System.Array в System.Array[], мы получаем исключение во время выполнения, поскольку истинный тип базового массива не может поддерживать операцию (x и x' только два представления одного и того же массива, и, очевидно, string[] не может быть сохранен в x). Эта несостоятельность в системе типов .NET, следовательно, имеет нежелательный побочный эффект: для большинства хранилищ в массивах требуются дополнительные издержки, чтобы гарантировать, что хранимое значение имеет тип, совместимый с базовым массивом. На мой взгляд, хорошо, что F # не позволяет вам делать это напрямую.

2 голосов
/ 27 октября 2011

Вы можете сделать это:

let x : float [] [] = Array.init 2 (fun x -> Array.zeroCreate 3)

let toArray (xs : #System.Array []) =
    Array.map (fun x -> x :> System.Array) xs

let x' : System.Array [] = toArray x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...