2017-10-15 34 views
1

我有以下代码斯卡拉:未绑定通配符类型

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一起工作过很长时间,所以如果你对如何让我的代码更加习惯自由地有任何建议的话!

回答

1

我可以看到让您的代码编译最短路径是:

-   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麻烦的。你使用它的方式在编译时不提供安全性。 type参数总是存在的,所以编译器不知道实际的类型是什么,所以编译器可以做的就是拒绝签名,因为它没有足够的信息来保证代码是安全的,强制你重写它与asInstanceOf

我想你应该选择的前两个路径之一:尝试

  1. 实现与适当的编译时检查,避开了asInstanceOf逃生舱口的实际类型安全的解决方案。不要使用scala.reflect,不要使用java.lang.Class,不要使用ClassTag - 所有这些东西都可能在运行时失败。或者,只要完全放弃类型安全,并在运行时发生正确的事情。你不会得到你想要的安全性,但你的代码会简单得多。

你在看什么似乎只是一个大杂烩,我 - Java反射,反射斯卡拉,类型参数,模式匹配,所有的方式混乱了,似乎并没有被的产品一致地思考你想在编译时和运行时发生什么。缺乏连贯性使得在没有写出比这更长的回答的情况下甚至难以批评。