删除类型字段

时间:2016-02-21 08:26:21

标签: scala type-erasure

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$1$StringHandler.handle(typeProblem.scala:11)
        at Main$$anon$1$Handler.handleAny(typeProblem.scala:5)

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

我正在寻找一种可以应用于父抽象类而不是污染所有孩子的解决方案。

我还尝试使用match,它的行为完全相同。或者类型字段是不可能的(我认为它们比类型参数更强大)?​​

1 个答案:

答案 0 :(得分:2)

通常使用匹配,在您的情况下,因为您不想添加任何类型参数,您必须指定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)