类型在Scala中作为键的键

ver*_*tti 8 types scala class map

我的游戏有

class Enemy
Run Code Online (Sandbox Code Playgroud)

谁可以改变我的人工智能/功能

trait Moving
trait VerticalMover extends Moving
trait RandomMover extends Moving
Run Code Online (Sandbox Code Playgroud)

等等.现在我需要根据特征获取预加载的东西.我想要做的是有一个Map接受所有特征,这些特征扩展了Moving作为键,然后是一些EnemyContainer作为预先加载特征相关内容的值.

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

val myEnemy = new Enemy with RandomMover 
val myDetails:EnemyContainer = enemyDetailsStore.get(myEnemy.getClass)
Run Code Online (Sandbox Code Playgroud)

Did*_*ont 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])
  }
}
Run Code Online (Sandbox Code Playgroud)

包装器本身(不是地图)

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) : _*))
}
Run Code Online (Sandbox Code Playgroud)

有了这个,你可以做到

import Typed._
val repository = TypedMap("foo", 12, "bar".typedAs[Any])
Run Code Online (Sandbox Code Playgroud)

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

你用它检索元素

repository[String] // returns "foo"
repository.get[Any] // returns Some("bar")
Run Code Online (Sandbox Code Playgroud)

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


oxb*_*kes 5

好吧,我假设您的敌人详细信息存储类型Map[Class[_ <: Moving], EnemyDetails].我怀疑像这样的东西:

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

要么:

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

甚至只是:

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

会为你做的.这段代码唯一的"问题"是它是O(N),因为它需要遍历映射,而不是简单的查找,它可以是O(1),或O(log N)