Akka演员 - 通用类型接收模式匹配

时间:2018-04-19 16:06:58

标签: scala pattern-matching akka actor

我有一个泛型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"

然而,它似乎永远不会出现在第二种情况下,并且总是打印出来"是" ...

如何打印"不"?

1 个答案:

答案 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 articlein 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 Boundsclass Test[S: ClassTag] extends Actor

您可以按如下方式阅读此签名:

  

类测试由类型S参数化,在隐式范围中有可用的ClassTag [S]。