Akka Actor - 按通用类型接收模式匹配
Akka Actor - Receive Pattern Match by Generic Type
我有一个通用 actor class,我想在接收方法中与通用类型进行模式匹配。
例如:
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"
然而,似乎它永远不会进入第二种情况,并且总是打印输出"yes"...
如何让它打印 "no"?
问题
您刚刚偶然发现了一个叫做 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 and 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
.
您可以通过以下方式阅读此签名:
A class Test is parametrized by type S, for which there is available ClassTag[S] in an implicit scope.
我有一个通用 actor class,我想在接收方法中与通用类型进行模式匹配。
例如:
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"
然而,似乎它永远不会进入第二种情况,并且总是打印输出"yes"...
如何让它打印 "no"?
问题
您刚刚偶然发现了一个叫做 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 and 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
.
您可以通过以下方式阅读此签名:
A class Test is parametrized by type S, for which there is available ClassTag[S] in an implicit scope.