我找到了一篇不错的文章:http://nut-cracker.azurewebsites.net/blog/2011/08/09/operator-overloading/,然后决定使用这篇文章中的信息来尝试一下 F#。我创建了自己的类型 Vector2D<'a>,支持加法和常数乘法:
事情是虽然它可以正常编译,但每次我尝试使用它时,都会出现错误:
错误信息为:
一个类型参数缺少约束条件'when ( ^a or ^?18259) : (static member ( / ) : ^a * ^?18259 -> ^?18260)'
此外,doSomething 的推断类型是: Vector2D<'a> -> Vector2D<'c>(需要成员 (/)、成员 (/) 和成员 get_One)
我的问题是:为什么可以使用成员 (*) 和 (+),但是使用 (/) 却不可能,即使它们以相同的方式定义? 另外,为什么推断类型说需要两个 (/) 成员?
type Vector2D<'a> = Vector2D of 'a * 'a
with
member this.X = let (Vector2D (x,_)) = this in x
member this.Y = let (Vector2D (_,y)) = this in y
static member inline (+) (Vector2D (lhsx, lhsy), Vector2D (rhsx, rhsy)) =
Vector2D(lhsx + rhsx, lhsy + rhsy)
static member inline ( * ) (factor, Vector2D (x, y)) =
Vector2D (factor * x, factor * y)
static member inline ( * ) (Vector2D (x, y), factor) =
Vector2D (factor * x, factor * y)
这很好,我在使用这些成员时没有观察到任何问题。 然后我决定加入对常数除法的支持(以便实现例如向量归一化):
static member inline (/) (Vector2D (x, y), factor) =
Vector2D (x / factor, y / factor)
事情是虽然它可以正常编译,但每次我尝试使用它时,都会出现错误:
let inline doSomething (v : Vector2D<_>) =
let l = LanguagePrimitives.GenericOne
v / l // error
错误信息为:
一个类型参数缺少约束条件'when ( ^a or ^?18259) : (static member ( / ) : ^a * ^?18259 -> ^?18260)'
此外,doSomething 的推断类型是: Vector2D<'a> -> Vector2D<'c>(需要成员 (/)、成员 (/) 和成员 get_One)
我的问题是:为什么可以使用成员 (*) 和 (+),但是使用 (/) 却不可能,即使它们以相同的方式定义? 另外,为什么推断类型说需要两个 (/) 成员?
(*)
的第一个定义会导致相同的乘法错误。在doSomething
中,l
的类型是未定义的,然而,将其注释为v
的组件类型并不能解决问题。我曾经遇到过类似的困惑,当我尝试使用通用向量来推断矩阵逻辑时。我放弃了,因为我再也无法理解IDE和编译器在做什么了。 - Vandroiy(*)
中间加上空格,否则它们可能会被解释为开始/结束注释。 - John Palmer