我有一些来自游戏的Scala代码,用于在onInteract(gameData: GameData, player: Player)
,GameObject
的{{1}}的每个实例上调用mutable.ArrayBuffer
方法。但是,有时这些gameobjects
会使用代码GameObject
从ArrayBuffer
中删除自己。由于这会改变gameobjects -= this
,Scala会抛出ArrayBuffer
。代码可以被认为类似于以下内容:
NullPointerException
并且每当删除一个对象时都会抛出异常。
我该如何解决这个问题?我想象一下for (gameobject <- gameobjects) {
if (/* some condition */) gameobjects -= gameobject
}
或至少ArrayBuffer
循环不适用于此。
答案 0 :(得分:1)
虽然我无法在scala 2.11.8中重现异常,但您可以看到结果不正确:
import scala.collection.mutable.ArrayBuffer
val a = ArrayBuffer(1, 2, 2, 3)
for (x <- a) {
if (x == 2) a-=x
}
// There's still a 2!
a: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
我怀疑发生了这种情况,因为当你开始迭代时,数组现在拥有更少的元素。
更好的,更加scala的方法是使用filter(或filterNot):
val a = ArrayBuffer(1, 2, 2, 3)
a.filter { _ != 2 } // == ArrayBuffer(1, 3)
答案 1 :(得分:1)
使用-=
删除ArrayBuffer
中的内容非常慢 - 您必须逐个元素搜索才能找到它,然后将所有内容随机播放到缓冲区的末尾。无论如何,你可能不应该这样做。
如果要同时进行迭代和删除,则应使用支持此功能的数据结构。 java.util.concurrent.ConcurrentHashMap
通常是一个不错的选择,如果你想通过身份查找你的对象并且你不会有重复。
例如:
val chm = new java.util.concurrent.ConcurrentHashMap[String, Int]
chm put ("fish", 1); chm put ("dish", 2); chm put ("wish", 3)
val e = chm.keys
e.hasMoreElements // true
e.nextElement // "wish"
e.hasMoreElements // true
chm remove "fish"
chm remove "dish" // empty now!!
e.nextElement // "dish"--was going to be the next key
e.hasMoreElements // false--now it realizes chm is empty
chm get "dish" // null, because it doesn't exist
使用Scala集合完全复制这种行为有点困难,所以为了保证您的安全,您可能希望像上面那样做一些事情。