我有一些问题,通过以下代码理解一般约束。 View是Xamarin框架中的基类(但这并不重要)
type GridCoordinates = (View * int * int * int * int)
type GridRecord = { children: GridCoordinates list}
根据这段代码我在这里得到一个编译错误
let x = { children = [(new BoxView( Color = Color.Green ), 0, 3, 0, 1)] }
^^^^^^^^^^^
Expression expected to have type View
现在BoxView的类型为View - 嗯。所以我想我会在其中添加一些通用约束
type GridCoordinates<'T when 'T :> View> = ('T * int * int * int * int)
type GridRecord = { children: GridCoordinates<View> list}
但是这仍然给了我同样的错误。所以我也向GridRecord添加了一个constrait
type GridCoordinates<'T when 'T :> View> = ('T * int * int * int * int)
type GridRecord<'T when 'T :> View> = { children: GridCoordinates<'T> list}
现在它编译。我甚至可以从GridCoordinates中删除约束,以便
type GridCoordinates<'T> = ('T * int * int * int * int)
type GridRecord<'T when 'T :> View> = { children: GridCoordinates<'T> list}
现在所有这些都是非常繁重的语法加上应该在GridCoordinates上的约束会侵入GridRecord的定义,这不是很好(imo)。
有人可以向我解释
a)为什么这有效,因为它有效 b)对此有更令人满意的解决方案吗?
答案 0 :(得分:6)
正如John在评论中提到的,F#并不(通常)隐式地将类强制转换为基类。因此,如果您创建BoxView
的新实例并在需要View
的某个地方使用它,则需要添加一个明确的 upcast :
以下内容适用于您的原始定义:
let x = { children = [(new BoxView( Color = Color.Green ) :> View, 0, 3, 0, 1)] }
在一些地方不需要向上播放(最重要的是,当您使用BoxView
作为采用View
的方法的参数时。我认为F#应该更智能一点,并且在这种情况下自动插入向上播放...