对于下面选项[实体] 的匹配,第三种情况需要详尽无遗。为什么?
entitiesMap 是包含不可变 Map [UUID,Entity] 的 var 。它在一个Akka Actor中被访问和更新,以避免线程问题。以下是接收功能的摘录:
class WorldActor extends Actor {
var world: World = null
override def receive = {
case WorldSet(w) =>
world = w
// get that state and apply it to its entity
case s: State if (world != null) =>
val uuid = new UUID(s.getUuid().getL1(), s.getUuid().getL2())
world.entitiesMap.get(uuid) match {
case Some(ent) =>
// Update entity's state
ent.setEntityState(s)
case None =>
Log.error("World doesn't contain entity uuid: " + uuid)
case other =>
Log.error("Received unknown message: " + other)
}
case AddEntity(ent) if (world != null && ent != null) =>
if (!world.entitiesMap.contains(ent.uuid))
world.entitiesMap += ent.uuid -> ent
case RemoveEntity(ent) if (world != null && ent != null) =>
if (world.entitiesMap.contains(ent.uuid))
world.entitiesMap -= ent.uuid
case other => // ignore
}
}
class World {
// Entity container
var entitiesMap = Map[UUID,Entity]()
}
以上代码会不时报告:
Received unknown message: None
为什么上面没有 case None 模式才能捕获它?
修改
我发现消息 State 就在消息 AddEntity 之前,即当 entitiesMap 尚未包含<时em>实体由消息 State 引用。
01:52 ERROR: [State] Received unknown message: None
uuid: 1b234d30-92ae-11e3-aa12-7071bcb09717
Thread: 152
01:52 ERROR: [State] Received unknown message: None
uuid: 1b234d30-92ae-11e3-aa12-7071bcb09717
Thread: 32
01:52 INFO: [AddEntity] 1b234d30-92ae-11e3-aa12-7071bcb09717: Cube@2f9c3beb
Thread: 152
毕竟这可能是一个线程问题吗?在一个演员?
编辑2
根据下面的海报建议,我已经记录了其他和无的类名,类加载器引用和类文件路径。他们都是一样的。
编辑3
其他==无 false
other.eq(无)是 false
other.equals(无) false
other.hashCode == None.hashCode
System.identityHashCode(其他)!= System.identityHashCode(无)
答案 0 :(得分:6)
这听起来像一个类加载器/类路径问题,其中None$
由两个类加载器加载而两个None $ .Module $不比较相等。
由于Map是不可变的,因此在添加之后,您已经创建了一个新的Map。假设外部加载器加载了新Map的类;然后当该地图返回None时,它将返回外星人None。
请注意,当您添加到非常小的地图时,它会使用new来创建下一个更大的地图;但经过一些这样的分配后,它会切换到HashMap。因此,竞争类加载器可能会改变您获得的地图的明显行为。
我不仅打印出类名,还打印出类加载器和加载类的位置。
答案 1 :(得分:1)
根据每个人的建议告诉我这个问题是一个类加载器问题和printing stack trace at None's construction time,我把它缩小到我使用Kryo来在通过网络传输之前序列化消息。
Kryo似乎是singleton objects can lead to my problem exactly的默认行为。 Kryo每次反序列化时都会重新加载 None ,导致 None 的 System.identityHashCode 不同。
问题是class reloading,解决方案是使用一个知道如何正确处理Scala对象以进行序列化的库,例如chill-scala。
package com.twitter.chill
// Singletons are easy, you just return the singleton and don't read:
// It's important you actually do this, or Kryo will generate Nil != Nil, or None != None
class SingletonSerializer[T](obj: T) extends KSerializer[T] {
def write(kser: Kryo, out: Output, obj: T) {}
def read(kser: Kryo, in: Input, cls: Class[T]): T = obj
}