Как убедить Scala.js использовать определенный Javascript метод для сравнения? - PullRequest
0 голосов
/ 03 октября 2018

Справочная информация: в реальных проектах используется Three.js с фасадом .И Three.js, и фасад определяют метод equals для многих типов, включая Vector3.Это небольшой пример, демонстрирующий функциональность equals.

У меня есть тип Javascript, который определяет метод equals:

MyType.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.scala фасад:

@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, e3 и e4 нет.Я не нашел способа, как я мог убедить это сделать это.Я попытался изменить подпись на 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 использовать реализацию equals, предоставленную классом JavaScript?Если нет, есть ли способ заставить его выдавать ошибку или предупреждение (желательно время компиляции), когда == используется в MyType?

Примечание: доступен полный готовый к использованию проектна GitHub .

1 Ответ

0 голосов
/ 04 октября 2018

Я нашел частичный ответ.Я могу использовать @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, но я сделалпока не нашел пути.Возможно, кто-то еще может прийти с более разумным решением?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...