Scala:未绑定通配符类型

Scala:未绑定通配符类型,scala,generics,Scala,Generics,我有以下代码 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](han

我有以下代码

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
}
导入scala.collection.mutable
导入scala.reflect.ClassTag
导入scala.reflect_
对象事件管理器{
变量处理程序:映射[Class[;mutable.Set(处理程序))
}
}
//如果事件被取消,则返回true,否则返回false
def fireEvent[A]
handlers.get(typeParam)匹配{
案例部分=>
s、 foreach(handler=>if(!cEvent.cancelled)handler.handle(event.asInstanceOf[\u
}
//如果活动已取消或未取消,则返回
取消
案例=>
handlers.get(typeParam)匹配{
case Some=>s.foreach(u.handle(event.asInstanceOf[\u
}
假的
}
}
}
特质事件

trait EventHandler[A我能看到的使代码编译的最短路径是:

-            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])}
-s.foreach(handler=>如果(!cEvent.cancelled)handler.handle(event.asInstanceOf[\u
+if(!cEvent.cancelled)handler.handle(event.asInstanceOf[t])的
-case Some=>s.foreach(u.handle(event.asInstanceOf[\u
+s.foreach{case handler:EventHandler[t]=>
+handler.handle(event.asInstanceOf[t])文件
但是,我想知道你为什么还要为
EventHandler
上的类型参数而烦恼。你使用它的方式在编译时没有提供安全性。类型参数总是存在的,因此编译器不知道实际的类型是什么,所以编译器所能做的就是拒绝注销,因为它没有足够的信息来进行验证确保代码是安全的,强制使用
asInstanceOf
覆盖代码

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

  • 尝试通过适当的编译时检查来实现真正的类型安全解决方案,避免使用
    asInstanceOf
    escape-hatch。不要使用
    scala.reflect
    ,不要使用
    java.lang.Class
    ,不要使用
    ClassTag
    ——所有这些都可能在运行时失败
  • 或者,完全放弃类型安全,让正确的事情在运行时发生。你不会得到你想要的安全,但是你的代码会简单得多
  • 对我来说,你现在所拥有的一切就像是一堆乱七八糟的东西——Java反射、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])}