类型在Scala中作为键的键

时间:2011-09-07 14:52:15

标签: class scala types map

我的游戏

class Enemy

我可以用

更改谁的AI /功能
trait Moving
trait VerticalMover extends Moving
trait RandomMover extends Moving

等等。现在我需要根据特征获取预加载的东西。我想要做的是有一个Map接受所有延伸移动的特征,然后将一些EnemyContainer作为预先加载特征相关内容的值。

但是我如何定义这样的Map以及如何格式化我的.get()以通过某个Enemy的实例来获取容器。类似的东西:

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

2 个答案:

答案 0 :(得分:11)

也许你可以包装Map [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])
  

repository:TypedMap = Map(java.lang.String - > foo,Int - > 12,Any - >   巴)

使用

检索元素
repository[String] // returns "foo"
repository.get[Any] // returns Some("bar")

我认为私有构造函数应该确保_ asInstanceOf是安全的。 inner可能会公开,因为它是不可变的。这样,Map的丰富界面将可用,但遗憾的是,不会创建另一个TypedMap

答案 1 :(得分:5)

好吧,我假设您的敌人详情商店的类型为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)