Game Screeps - найти языки с фильтром и статической типизацией (Scala) - как правильно фасадировать?

Я пытаюсь перенести код учебника JavaScript на Scala.js и застрял на фильтрации структур - любые предложения будут оценены.

Оригинальный код:

// If creep is supposed to transfer energy to a structure
if (creep.memory.working == true) {

    // Find closest spawn, extension or tower which is not full
    var structure = creep.pos.findClosestByPath(FIND_MY_STRUCTURES, {
        filter: (s) => (s.structureType == STRUCTURE_SPAWN
        || s.structureType == STRUCTURE_EXTENSION
        || s.structureType == STRUCTURE_TOWER)
        && s.energy < s.energyCapacity });

Код в Scala.js:

val structure = Option[Structure](creep.pos.findClosestByPath[Structure](FIND_MY_STRUCTURES,
FindFilter[Structure](structure => {
   (structure.structureType == STRUCTURE_SPAWN ||
    structure.structureType == STRUCTURE_EXTENSION ||
    structure.structureType == STRUCTURE_TOWER) &&
    structure.energy < structure.energyCapacity })))

Проблема в том, что не все типы структур имеют .energy, поэтому это не будет компилироваться, несмотря на то, что фильтрованные имеют?

Я попытался определить трейт HasEnergy (похожий на интерфейс JavaScript) и использовать его как FindFilter[Structure with HasEnergy], который компилируется, но теперь я получаю ошибку типа во время выполнения -> TypeError: a.k is not a function.

Мои фасады выглядят так:

@js.native
trait HasEnergy extends js.Object {
  val energy: Int
  val energyCapacity: Int
}

@js.native
trait Structure extends RoomObject with HasID {
  val hits: UndefOr[Int]
  val hitsMax: UndefOr[Int]
  val id: String
  val structureType: String
  def destroy(): Int
  def isActive(): Boolean
  def notifyWhenAttacked(enabled: Boolean): Int
}

person LXK    schedule 14.01.2017    source источник


Ответы (1)


Хорошо, вот решение, которое я придумал:

  val structure = {
    Option(creep.pos.findClosestByPath[OwnedStructureWithEnergy](FIND_MY_STRUCTURES, FindFilter[OwnedStructureWithEnergy](s =>
      ((s.structureType == STRUCTURE_SPAWN) ||
        (s.structureType == STRUCTURE_EXTENSION) ||
        (s.structureType == STRUCTURE_TOWER)) &&
        (s.energy < s.energyCapacity))))
  }

Оказывается, в моем фасаде findClosestByPath произошла ошибка. Правильная версия для API поддерживает FindFilter и FindFilterAlgorithm — первый отсутствовал в моем отображении. Правильный вариант теперь выглядит так:

  def findClosestByPath[T](typ: Int, opts: FindFilter[T] | FindFilterAlgorithm[T] = ???): T
  @JSName("findClosestByPath")

Теперь, чтобы использовать доступ к членам через точку, я добавил трейт OwnedStructureWithEnergy:

@js.native
trait OwnedStructureWithEnergy extends OwnedStructure {
  val energy: Int = js.native
  val energyCapacity: Int = js.native
}
person LXK    schedule 14.01.2017