Тип класса как ключ в карте в Scala - PullRequest
7 голосов
/ 07 сентября 2011

В моей игре

class Enemy

кто такой AI / функциональность, которую я могу изменить с помощью

trait Moving
trait VerticalMover extends Moving
trait RandomMover extends Moving

и так далее. Теперь мне нужно выбрать предварительно загруженный материал на основе черты. То, что я хотел бы сделать, это иметь карту, которая принимает все черты, которые расширяют Moving в качестве ключей, а затем некоторые EnemyContainer в качестве значения, для которых предварительно загружен контент, связанный с чертами.

Но как мне определить такую ​​Карту и как отформатировать мой .get (), чтобы получить контейнер экземпляром какого-то врага. Что-то вроде:

val myEnemy = new Enemy with RandomMover 
val myDetails:EnemyContainer = enemyDetailsStore.get(myEnemy.getClass)

Ответы [ 2 ]

11 голосов
/ 07 сентября 2011

Может быть, вы могли бы обернуть карту [Manifest, Any], гарантируя, что значения соответствуют ключам манифеста.

Возможный набросок этого. Сначала маленький помощник

class Typed[A](value: A)(implicit val key: Manifest[A]) {
  def toPair: (Manifest[_], Any) = (key, value)
}
object Typed {
  implicit def toTyped[A: Manifest](a: A) = new Typed(a)
  implicit def toTypable[A](a: A) = new {
    def typedAs[T >: A : Manifest] = new Typed[T](a)(manifest[T])
  }
}

тогда сама оболочка (которая не является картой)

class TypedMap private(val inner: Map[Manifest[_], Any]) {
  def +[A](t: Typed[A]) = new TypedMap(inner + t.toPair)
  def +[A : Manifest](a: A) = new TypedMap(inner + (manifest[A] -> a))
  def -[A : Manifest]() = new TypedMap(inner - manifest[A])
  def apply[A  : Manifest]: A = inner(manifest[A]).asInstanceOf[A]
  def get[A : Manifest]: Option[A] = inner.get(manifest[A]).map(_.asInstanceOf[A])
  override def toString = inner.toString
  override def equals(other: Any) = other match {
    case that: TypedMap => this.inner == that.inner
    case _ => false
  }
  override def hashCode = inner.hashCode
}

object TypedMap {
  val empty = new TypedMap(Map())
  def apply(items: Typed[_]*) = new TypedMap(Map(items.map(_.toPair) : _*))
}

С этим вы можете сделать

import Typed._
val repository = TypedMap("foo", 12, "bar".typedAs[Any])

хранилище: TypedMap = Map (java.lang.String -> foo, Int -> 12, Any -> бар)

Вы получаете элементы с

repository[String] // returns "foo"
repository.get[Any] // returns Some("bar")

Я думаю, что частный конструктор должен обеспечить безопасность _ asInstanceOf. inner может быть оставлено публичным, так как оно является неизменным. Таким образом, будет доступен богатый интерфейс Map, но, к сожалению, не для создания другого TypedMap.

5 голосов
/ 07 сентября 2011

Ну, я предполагаю, что ваш вражеский магазин имеет тип Map[Class[_ <: Moving], EnemyDetails].Я подозреваю, что что-то вроде:

//gives a Map[Class[_ <: Moving], EnemyDetails] for all matching keys
enemyDetailsStore.filterKeys(_ isInstance myEnemy) 

Или:

//Iterable[EnemyDetails]
enemyDetailsStore collect { case (c, d) if c isInstance myEnemy => d }

Или даже просто:

//Option[EnemyDetails]
enemyDetailsStore collectFirst { case (c, d) if c isInstance myEnemy => d }

Подойдет для вас.Единственная «проблема» с этим кодом состоит в том, что это O (N), так как для него требуется обход карты, а не простой поиск, который будет O (1) или O (log N)

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