我需要调用一个函数,它将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 []'
我该如何解决这个问题?
提前致谢。
答案 0 :(得分:4)
当's[]
使.NET类型系统不健全时,将't[]
视为's :> 't
的能力(可能是因为Java做同样的事情)。不幸的是,C#遵循.NET允许这样做。
因为它是一个.NET运行时功能,你也可以通过装箱和拆箱在F#中完成:
let x : float[][] = Array.init 2 (fun x -> Array.zeroCreate 3)
let x' = (box x) :?> System.Array[]
这避免了在Ramon的解决方案中映射每个元素的开销。
要了解为什么这会使.NET类型系统不健全,请考虑以下事项:
x'.[0] <- upcast [| "test" |] // System.ArrayTypeMismatchException
即使我们将System.Array
类型的值存储到System.Array[]
中,我们也会在运行时获得异常,因为底层数组的真实类型不支持该操作({{1} }和x
只是同一个数组的两个视图,显然x'
无法存储到string[]
中)。因此,.NET类型系统中的这种不健全具有不希望的副作用,即需要将大多数存储的额外开销分配到数组中以确保存储的值具有与底层数组兼容的类型。在我看来,F#阻止你直接这样做是件好事。
答案 1 :(得分:2)
你可以这样做:
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