Scala Akka - generics type in receive handler

家住魔仙堡 提交于 2020-01-24 22:13:17

问题


I am trying to get my head around on what is best way to code this implementation. To give you example, here is my DAO handler code looks like

trait IDAOHandler[+T]  {
  def create[U <: AnyRef: Manifest](content: U): Try[String]
}

class MongoDAOHAndler extends IDAOHandler[+T]...

So I am creating actor that will handle all my persistence task that includes serializing the content and updating MongoDB database.

So I am using akka and the trick is in receive method, how do i handle generics type parameter. Even though my actor code is non-generic, but the messages it is going to receive will be generic type and based on content type in createDAO I was planning to get appropriate DAO handler (described aboe) and invoke the method.

case class createDAO[T](content: T) (implicit val metaInfo:TypeTag[T])

class CDAOActor(daofactory: DAOFactory) extends BaseActor {
  def wrappedReceive = {
    case x: createDAO[_] => pmatch(x)
  }

  def pmatch[A](c: createDAO[A]) {
     //getting dao handler which will not work because it needs manifest
  }
}

Let me know if there are any other ways to re-write this implementation.


回答1:


You might already know this, but a little background just to be sure: In Scala (and Java) we have what is called type erasure, this means that the parametric types are used to verify the correctness of the code during compile time but is then removed (and "does not give a runtime cost", http://docs.oracle.com/javase/tutorial/java/generics/erasure.html). Pattern matching happens during runtime so the parametric types are already erased.

The good news is that you can make the Scala compiler keep the erased type by using TypeTag like you have done in your case class or ClassTag which contains less information but also keeps the erased type. You can get the erased type from the method .erasure (.runtimeClass in Scala 2.11) which will return the Java Class of the T type. You still wont be able to use that as the type parameter for a method call as that again happens compile time and you are now looking at that type in runtime, but what you can do is to compare this type during runtime with if/else or patternmatching.

So for example you could implement a method on your daofactory that takes a Class[_] parameter and returns a DAO instance for that class. In pmatch you would then take the erased type out of the tag and pass on to it.

Here is some more info about the tags, why they exist and how they work: http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html




回答2:


I took a bit different approach, kind of dispatcher pattern, so here is the revised code

trait IDAOProcess 
{
  def process(daofactory:IDAOFactory,sender:ActorRef) 
}

case class createDAO[T <: AnyRef : Manifest](content:T) (implicit val metaInfo:TypeTag[T]) extends IDAOProcess
{
  def process(daofactory:IDAOFactory,sender:ActorRef)
  {
    for ( handler <- daofactory.getDAO[T] ) 
    {
      handler.create(content)
    }
  }
}

class DAOActor(daofactory:IDAOFactory) extends BaseActor  
{
  def wrappedReceive =
  {
    case x:IDAOProcess => 
      {
        x.process(daofactory,sender)
      }
  }
}


来源:https://stackoverflow.com/questions/24685146/scala-akka-generics-type-in-receive-handler

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