擦除类型字段

Erasure of type fields

abstract class Handler {
  type Message

  def handleAny(msg: Any) {
    if (msg.isInstanceOf[Message]) handle(msg.asInstanceOf[Message]) // fix me!
  }

  def handle(msg: Message)
}

class StringHandler extends Handler {
  override type Message = String

  def handle(msg: Message) { println(s"handling: $msg") }
}

val h = new StringHandler
h.handleAny("ahoj")
h.handleAny(true)

warning: abstract type Handler.this.Message is unchecked since it is
 eliminated by erasure
                if(msg.isInstanceOf[Message]) handle(msg.asInstanceOf[Message])
                                   ^
one warning found
handling: ahoj
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.String
        at Main$$anon$StringHandler.handle(typeProblem.scala:11)
        at Main$$anon$Handler.handleAny(typeProblem.scala:5)

如何更改代码段(不更改接口或用类型参数替换类型字段)以按预期工作,即仅处理由指定的消息类型字段?

我正在寻找一种可以应用于父摘要 class 而不是污染所有子级的解决方案。

我也尝试使用 match 并且它的行为完全相同。还是类型字段不可能实现这种事情(我认为它们比类型参数更强大)?​​

通常使用匹配,在您的情况下,由于您不想添加任何类型参数,因此您必须指定 ClassTag(我认为)。

大致如下:

import scala.reflect.ClassTag

abstract class Handler {
  type Message <: Any
  implicit val tag: ClassTag[Message]

  def handleAny(msg: Any): Unit = {
    msg match {
      case tag(message) =>
        handle(message)
      case _ =>
        throw new IllegalArgumentException(s"Argmument MUST BE a 'Message' but $msg is not!")
    }
  }

  def handle(msg: Message): Unit
}

object StringHandler extends Handler {
  override type Message = String
  // lazy is important here!
  implicit lazy val tag: ClassTag[Message] = ClassTag(classOf[String])

  def handle(msg: Message): Unit =  { println(s"handling: $msg") }
}


StringHandler.handleAny("ahoj")
StringHandler.handleAny(true)