2017-10-15 83 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反射,反射斯卡拉,類型參數,模式匹配,所有的方式混亂了,似乎並沒有被的產品一致地思考你想在編譯時和運行時發生什麼。缺乏連貫性使得在沒有寫出比這更長的回答的情況下甚至難以批評。