我有一个泛型actor类,我想在receive方法中使用泛型类型进行模式匹配。
例如:
class Test[S] extends Actor {
override def receive: Receive = {
case _: S => println("yes")
case _ => println("no")
}
}
val ac = system.actorOf(Props(new Test[Int]))
ac ! "abc" // expect print "no"
ac ! 3 // expect print "yes"
然而,它似乎永远不会出现在第二种情况下,并且总是打印出来"是" ...
如何打印"不"?
答案 0 :(得分:3)
你偶然发现了一个名为 type erasure 的东西。这意味着,在编译期间删除了泛型类型信息(JVM不了解泛型)。所以在运行时,你的演员看起来像这样:
class Test extends Actor {
override def receive: Receive = {
case _: Object => println("yes")
case _ => println("no")
}
}
这就是为什么ac ! "abc"
以及ac ! 3
将始终与第一种情况相匹配的原因。
幸运的是,Scala提供了有助于克服此问题的机制。您可以详细了解他们in this article和in the docs。
tldr;您可以找到一个有效的示例here, on Scastie。
您应该使用以下机制之一: ClassTag 。您可以将其视为作为对象,它包含运行时在编译时可用的所有信息。
import scala.reflect.ClassTag
object Main extends App {
class Test[S](implicit ct: ClassTag[S]) extends Actor {
override def receive: Receive = {
case _: S => println("yes")
case _ => println("no")
}
}
val system = ActorSystem()
val ac = system.actorOf(Props(new Test[Int]))
ac ! "abc" // expect print "no"
ac ! 3 // expect print "yes"
system.terminate()
}
您可能想知道我们在哪里可以找到ClassTag [T]的隐式实例。幸运的是,编译器将按需提供一个。
奖励:您可以重写class Test[S](implicit ct: ClassTag[S]) extends Actor
以使用所谓的Context Bounds:class Test[S: ClassTag] extends Actor
。
您可以按如下方式阅读此签名:
类测试由类型S参数化,在隐式范围中有可用的ClassTag [S]。