【问题标题】:Class type as key in map in Scala类类型作为 Scala 中映射的键
【发布时间】:2011-11-12 06:02:12
【问题描述】:

我的游戏有

class Enemy

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

trait Moving
trait VerticalMover extends Moving
trait RandomMover extends Moving

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

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

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

【问题讨论】:

  • 你的意思是你想让enemyDetailsStoremyEnemy扩展VerticalMover时返回一件事,如果它扩展RandomMover则返回另一件事?如果两者都扩展呢?
  • 是的,我就是这个意思。但我开始怀疑我的整个想法是否合理。也许我应该在特征中嵌入一些关键字符串并将其用作关键。因此,通过 trait 线性化,最后一个覆盖 trait 将设置 EnemyContainer,换句话说就是用于显示敌人的纹理。
  • 大多数时候,特征/接口的意义在于说“我知道怎么做 X”,同时允许 X 的不同实现。其他细节,我认为最自然的设计是让 Moving 特征直接在其上具有某种 getMovingStrategymove 方法,您可以在垂直和随机移动子特征中相应地实现。

标签: class scala types map


【解决方案1】:

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

存储库:TypedMap = Map(java.lang.String -> foo, Int -> 12, Any -> 条)

你用

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

我认为私有构造函数应该确保 _asInstanceOf 是安全的。 inner 可以公开,因为它是不可变的。这样Map的丰富接口就可以使用了,可惜不能再创建一个TypedMap

【讨论】:

    【解决方案2】:

    好吧,我假设你的敌人详细信息存储是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)

    【讨论】:

      猜你喜欢
      • 2018-11-21
      • 2019-09-06
      • 1970-01-01
      • 2019-01-18
      • 2012-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多