Preserving type arguments in Akka receive

半腔热情 提交于 2019-12-07 14:37:22

问题


This question has kind of been answered by Roland Kuhn in this post, however, despite several comments asking for detail, he didn't bother to share the complete answer.

Here's what I want to do: I have a wrapper class case class Event[T](t: T) of which I send instances to an Akka actor. In the receive method of that actor, I then want to distinguish between Event[Int] and Event[String], which obviously isn't so simple due to type erasure.

What Roland Kuhn shares in the mentioned post is that "there is exactly one way to do it", that is, embodying the type information within the message. So I did this:

case class Event[T](t: T)(implicit val ct: ClassTag[T])

Even though asked by different people to provide it, Roland Kuhn does not say what to actually do within the receive method then. Here's what I tried.

def receive = {
  case e: Event =>
    if (e.ct.runtimeClass == classOf[Int])
      println("Got an Event[Int]!")
    else if (e.ct.runtimeClass == classOf[String])
      println("Got an Event[String]!")
    else
      println("Got some other Event!")
  case _ =>
    println("Got no Event at all!")
}

This is the best I could come up with as it's hard to wrap one's head around Scala's reflection jungle. It's not compiling, though:

value ct is not a member of Any
else if (e.ct.runtimeClass == classOf[String])
           ^

Thus, I am asking specifically about what the receive method should look like.


回答1:


After fixing the error Event takes type parameters:

def receive = {
  case e: Event[_] =>
    if (e.ct.runtimeClass == classOf[Int])
      println("Got an Event[Int]!")
    else if (e.ct.runtimeClass == classOf[String])
      println("Got an Event[String]!")
    else
      println("Got some other Event!")
  case _ =>
    println("Got no Event at all!")
}

the code compiles. It can be slightly simplified by not looking inside the ClassTags (of course, the implementation of ClassTag#equals is going to compare the classes):

import scala.reflect.{ClassTag, classTag}

def receive = {
  case e: Event[_] =>
    if (e.ct == ClassTag.Int) // or classTag[Int]
      println("Got an Event[Int]!")
    else if (e.ct == classTag[String])
      println("Got an Event[String]!")
    else
      println("Got some other Event!")
  case _ =>
    println("Got no Event at all!")
}



回答2:


You can also do pattern matching on the internal variable inside a nested class in which case it is more concise, you can utilise various pattern matching tricks and you don't even need ClassTag: eg

case class Event[T](t: T)    

def receive = {
  case Event(t: Int) => 
    println("Int")
  case Event((_: Float | _: Double)) => 
    println("Floating Point")
  case Event(_) =>
    println("Other")
}


来源:https://stackoverflow.com/questions/40578024/preserving-type-arguments-in-akka-receive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!