2017-10-15 12 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に型パラメータでわざわざ私はなぜだろうか。あなたがそれを使用している方法は、コンパイル時に安全性を提供しません。型パラメータは常に実在しているので、コンパイラは実際の型が何であるか分からないので、コードが安全であることを保証するのに十分な情報がないため、コンパイラはすべてサインオフを拒否します。それはasInstanceOfです。

私はあなたが前方に2つのパスのいずれかを選択すべきだと思う:asInstanceOfエスケープハッチをeschewing、適切なコンパイル時のチェックで実際にタイプセーフソリューションを達成するために

  1. 試みを。 scala.reflectを使用しないでください。java.lang.Classを使用しないでください。ClassTagを使用しないでください。これらのすべてが実行時に失敗する可能性があります。
  2. または、型の安全性をあきらめて、実行時に適切なことが起こるようにしてください。おそらくあなたが試みた安全は得られませんが、あなたのコードはずっと簡単になります。

Javaリフレクション、スカラ反射、型パラメータ、パターンマッチングなどは、私にとっては奇妙なものです。あなたがコンパイル時と実行時とで何をしたいかについての一貫した考え方。一貫性の欠如は、それよりもはるかに長い答えを書くことなく批判することさえ困難にする。

関連する問題