来自Array Covariance文章:
元素类型是引用类型的数组是协变的。 [...]它被添加到CLR中,因为Java需要它,而CLR设计者希望能够支持类似Java的语言。
CLR支持数组协方差,但是如何在F#中使用这个方便的功能?
type Foo () = class end
type Bar () = inherit Foo ()
// must have type Foo []
let foo : Foo [] = Array.create 1 (Bar ())
// ^^^^^^ must not cast to Foo
// must throw ArrayTypeMismatchException
foo.[0] <- Foo ()
在示例中,我希望foo
在场景后面存储Bar
数组,就像在CLR中实现一样。
答案 0 :(得分:6)
在C#允许类型之间隐式转换的许多地方,F#需要显式转换。
F#编译器甚至不允许从Bar[]
直接转换为Foo[]
(类型'Bar []'没有任何正确的子类型,也不能用作源代码类型测试或运行时强制。),您需要先转换为object
。
let foo = Array.create 1 (Bar ()) :> obj :?> Foo[]
顺便说一句,我不会将数组协方差称为一个方便的特性,它会导致比它解决的问题更多的问题。
答案 1 :(得分:6)
仅仅为了记录,也许最值得注意的是数组协方差很有用的情况是当你有一个函数需要Foo[]
并且你想用Bar[]
参数调用它时。这是F#泛型所涵盖的内容,因为您可以使用#Foo[]
语法编写适用于从给定类型继承的任何类型的函数:
type Foo () = class end
type Bar () = inherit Foo ()
let doFooThings (foos:Foo[]) = ()
let doFooThingsBetteer (foos:#Foo[]) = ()
let bars = [| Bar() |]
doFooThings bars // error: The type 'Foo' does not match the type 'Bar'
doFooThingsBetteer bars // no error!