如何使数组协方差在 F# 中工作
How to make Array Covariance work in F#
来自Array Covariance篇文章:
Arrays where the element type is a reference type are covariant. [...] It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages.
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 中实现的那样。
在许多 C# 允许类型间隐式转换的地方,F# 需要显式转换。
F# 编译器甚至不允许从 Bar[]
到 Foo[]
的直接转换(类型 'Bar []' 没有任何适当的子类型,不能使用作为类型测试或运行时强制转换的来源。),您需要先转换为 object
。
let foo = Array.create 1 (Bar ()) :> obj :?> Foo[]
顺便说一句,我不会将数组协方差称为方便的功能,它导致的问题多于解决的问题。
仅作记录,也许数组协方差最有用的最值得注意的情况是当您有一个接受 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!
来自Array Covariance篇文章:
Arrays where the element type is a reference type are covariant. [...] It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages.
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 中实现的那样。
在许多 C# 允许类型间隐式转换的地方,F# 需要显式转换。
F# 编译器甚至不允许从 Bar[]
到 Foo[]
的直接转换(类型 'Bar []' 没有任何适当的子类型,不能使用作为类型测试或运行时强制转换的来源。),您需要先转换为 object
。
let foo = Array.create 1 (Bar ()) :> obj :?> Foo[]
顺便说一句,我不会将数组协方差称为方便的功能,它导致的问题多于解决的问题。
仅作记录,也许数组协方差最有用的最值得注意的情况是当您有一个接受 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!