我有一个名为' Pane' (想想玻璃窗格)实现IPane:
type IPane =
abstract PaneNumber : int with get, set
abstract Thickness : float<m> with get, set
abstract ComponentNumber : int with get, set
abstract Spectra : IGlassDataValues with get, set
...
type Pane(paneNumber, componentNumber, spectra, ...) =
let mutable p = paneNumber
let mutable n = componentNumber
let mutable s = spectra
...
interface IPane with
member this.PaneNumber
with get() = p
and set(value) = p <- value
member this.ComponentNumber
with get() = n
and set(value) = n <- value
member this.Spectra
with get() = s
and set(value) = s <- value
...
我创建了一个窗格列表(窗格列表):
let p = [ p1; p2 ]
但是我需要将它转换为IPane列表,因为这是另一个函数中的参数类型。以下代码产生错误:
let p = [ p1; p2 ] :> IPane list
'Type constraint mismatch. The type
Pane list
is not compatible with type
IPane list
The type 'IPane' does not match the type 'Pane'
当Pane实施IPane时,这很令人困惑。简单地将Pane list对象作为参数传递给所需的函数也会产生错误。
如何将窗格列表转换为IPane列表?
答案 0 :(得分:8)
F#不会以你想要的方式允许继承。
更好的方法是使用:
[p1 ;p2] |> List.map (fun x -> x:> IPane)
或者,您可以将功能更改为使用此类
let f (t:#IPane list) = ()
在这里你可以做f [p1;p2]
因为#
告诉编译器任何继承自IPane
的类型都没问题。
答案 1 :(得分:3)
另一种方式是这样的:
let p = [p1; p2] : IPane list
// or equivalently
let p : IPane list = [p1; p2]
在原始代码中,发生的事情是,首先它推断出[p1; p2]
的类型没有任何约束,它发现是Pane list
,然后它尝试将其向上转换为IPane list
},它不能做,因为F#有严格的方差规则:即使Pane
是IPane
的子类型,Pane list
也不是IPane list
的子类型。
在上面的代码中,另一方面,它不是试图推断[p1; p2]
的类型,而是验证它是否可以匹配给出的类型IPane list
;在这样做时,它隐含地将单个列表元素p1
和p2
向上翻转为IPane
。
答案 2 :(得分:1)
解决方案比我想象的要容易。
我将p1和p2定义为:
let p1 = new Pane(1, 2, blah, blah)
let p2 = new Pane(2, 2, blah, blah)
但是,如果我此时将它们作为IPanes投射,那么一切正常:
let p1 = new Pane(1, 2, blah, blah) :> IPane
let p2 = new Pane(2, 2, blah, blah) :> IPane
上面的John Palmer的解决方案可能更加严谨,因为原始窗格对象被维护为具体类型。