如何说服Scala.js使用Javascript定义的方法进行比较?



背景:真正的项目使用带有立面的Three.js。三.js和立面都定义了许多类型的equals方法,包括Vector3。这是一个演示equals功能的小示例。

我有一个Javascript类型,它定义了一个equals方法:

我的类型.js:

function MyType(x, y) {
this.x = x;
this.y = y;
}
MyType.prototype.constructor = MyType;
MyType.prototype.equals = function(that) {
return (this.x === that.x) && (this.y === that.y);
};
MyType.prototype.toString = function() {
return "MyType(" + this.x + "," + this.y + ")";
};

MyType.scalafaçade:

@js.native
@JSGlobal("MyType")
class MyType(var x: Double, var y: Double) extends js.Any {
def equals(that: MyType): Boolean = js.native
override def toString: String = js.native
}

问题是Scala.js似乎提供了自己的equals实现,它隐藏了Javascript类提供的实现以进行比较。

在我的测试套件中,我有以下代码:

class MyTypeTest extends FunSuite {
test("Basic test") {
val my0 = new MyType(0, 0)
val my1 = new MyType(0, 0)
val e1 = my0 equals my1
val e3 = my0 == my1
val e4 = my0 === my1
assert(e1, "equals")
assert(e3, "==")
assert(e4, "===")
}
}

虽然e1线称为MyType.equals,但e3e4则不然。我没有找到任何方法如何说服它这样做。我尝试将签名更改为def equals(that: js.Any): Boolean甚至override def equals(that: Any): Boolean,但仍然没有运气。

我能做的最好的事情就是拉皮条====运算符并使用它:

object MyType {
implicit class PimpEquals(val myType: MyType) {
override def equals(that: Any): Boolean = {
that match {
case myTypeThat: MyType =>
myType.equals(myTypeThat) // calls MyType.equals
case _ =>
myType.equals(that) // calls java.lang.Object.equals
}
}
def ====(that: Any): Boolean = {
equals(that)
}
}
}

(拉皮条的equals不考虑用于正常==,考虑到语言的定义,这并不奇怪(。====的问题仍然是有人可以错误地使用==运算符并且没有警告。

有没有办法说服 Scala.js 使用 JavaScript 类提供的equals实现?如果没有,当MyType上使用==时,有没有办法让它发出错误或警告(最好是编译时(?

注意:GitHub 上提供了完整的即用型项目。

我找到了部分答案。我可以使用@JSName使运算符重载==。它不能被覆盖,因为它是最终的,但它可以被重载:

@js.native
class MyType(var x: Double, var y: Double) extends js.Any {
def equals(that: MyType): Boolean = js.native
@JSName("equals")
def ==(that: MyType): Boolean = js.native
@JSName("equalsNot")
def !=(that: MyType): Boolean = js.native
override def toString: String = js.native
}

注意我正在导入equalsNot作为!=。这样的功能不存在,但是当有人尝试使用!=时,我希望得到错误。如果不重载,它将静默工作,但语义与==不同。

我宁愿以某种方式覆盖equals以便使用==!=的自然 Scala 实现,但到目前为止我没有找到一种方法。也许其他人能够提供一些更智能的解决方案?

最新更新