Scala:未绑定的通配符类型



我有以下代码

import scala.collection.mutable
import scala.reflect.ClassTag
import scala.reflect._
object EventManager {
var handlers: Map[Class[_ <: Event], mutable.Set[EventHandler[_ <: Event]]] = Map()
def registerHandler [A <: Event](handler: EventHandler[A])(implicit tag: ClassTag[A]): Unit = {
val typeParam = tag.runtimeClass.asSubclass(classOf[Event])
handlers.get(tag.runtimeClass.asSubclass(classOf[Event])) match {
case Some(_) => handlers(typeParam) += handler.asInstanceOf[EventHandler[Event]]
case None => handlers += (typeParam -> mutable.Set(handler))
}
}
//Returns true if the event was cancelled, false otherwise
def fireEvent[A <: Event](event: A)(implicit tag: ClassTag[A]): Boolean = {
val typeParam = tag.runtimeClass.asSubclass(classOf[Event])
event match {
case cEvent: CancellableEvent =>
handlers.get(typeParam) match {
case Some(s) =>
s.foreach(handler => if (!cEvent.cancelled) handler.handle(event.asInstanceOf[_ <: Event]))
case None =>
}
//Return if the event was cancelled or not
cEvent.cancelled
case _ =>
handlers.get(typeParam) match {
case Some(s) => s.foreach(_.handle(event.asInstanceOf[_ <: Event]))
case None =>
}
false
}
}
}
trait Event
trait EventHandler[A <: Event]{
def handle(event: A)
}
trait CancellableEvent extends Event{
var cancelled: Boolean = false
}

它旨在成为一个简单的事件处理系统,尽管我无法想出如何修复我遇到的这个烦人的错误。

Error:(31, 91) unbound wildcard type
s.foreach(handler => if (!cEvent.cancelled) handler.handle(event.asInstanceOf[_ <: Event]))

老实说,我不知道我能做些什么来解决这个问题。此外,我使用Scala的时间还不长,所以如果你对如何使我的代码更地道有任何建议,请放心!

我能看到的编译代码的最短路径是:

-            s.foreach(handler => if (!cEvent.cancelled) handler.handle(event.asInstanceOf[_ <: Event]))
+            s.foreach{case handler: EventHandler[t] =>
+              if (!cEvent.cancelled) handler.handle(event.asInstanceOf[t])}
-          case Some(s) => s.foreach(_.handle(event.asInstanceOf[_ <: Event]))
+          case Some(s) =>
+            s.foreach{case handler: EventHandler[t] =>
+              handler.handle(event.asInstanceOf[t])}

但是,我想知道您为什么还要为EventHandler上的类型参数而烦恼。您使用它的方式在编译时没有提供安全性。类型参数总是存在的,所以编译器不知道实际的类型是什么,所以编译器所能做的就是拒绝注销,因为它没有足够的信息来确保代码的安全,迫使你用asInstanceOf覆盖它。

我认为你应该从两条前进道路中选择一条:

  1. 尝试通过适当的编译时检查来实现一个真正类型安全的解决方案,避免使用asInstanceOf转义填充。不要使用scala.reflectjava.lang.ClassClassTag——所有这些都可能在运行时失败
  2. 或者,完全放弃类型安全,在运行时做正确的事情。你不会得到你可能想要的安全性,但你的代码会简单得多

对我来说,你现在所拥有的似乎是一个大杂烩——Java反射、Scala反射、类型参数、模式匹配,所有这些都以一种似乎不是在编译时和运行时连贯思考的产物的方式混乱起来。缺乏连贯性使得即使不写一个比这更长的答案也很难进行批评。

最新更新