是否有可能克服akka接收中的类型擦除?

时间:2013-12-06 03:58:25

标签: scala akka type-erasure

我有一个特征并且实现了akka actor,由于类型擦除而无法正确区分传入消息的类型,因此第一种情况是匹配所有消息。

我正在使用scala 2.10.x,并且从阅读许多其他答案我知道可以使用TypeTagClassTag恢复特征内的类型信息,但我无法想象如何在akka接收中应用它(如果可能的话)。

我(非常简化)的例子如下。是否可以正确匹配泛型类型?

package com.ebay.box.canada.batch.jobs.siteMap

import akka.actor.Actor
import akka.actor.ActorSelection
import akka.actor.Actor.Receive
import scala.reflect.ClassTag


trait MessageProcessor[A,B] {
  this: Actor =>

  val destA: ActorSelection
  val destB: ActorSelection

  def processA(a: A): A
  def processB(a: B): B

  def receive: PartialFunction[Any,Unit] = {
    case a: A =>
      destA ! processA(a)
    case b: B =>
      destB ! processB(b)
  }
}

class StringIntProcessor(val destA: ActorSelection, val destB: ActorSelection) extends MessageProcessor[String,Int] with Actor {
  def processA(a: String) = { a + "1" }
  def processB(b: Int) = { b + 1 }
}

1 个答案:

答案 0 :(得分:0)

我不认为你可以在你的特征中获得TypeTag[A]ClassTag[A] - 类型标签/类标签始终是方法调用的隐式参数列表的一部分。您可以使用隐式构造函数参数来使用抽象类:

import scala.reflect.runtime.universe._

abstract class MessageProcessor[A,B]()(implicit cta: ClassTag[A], ctb: ClassTag[B]) {
   def receive = {
     case a: Any if a.getClass() == cta.runtimeClass =>
       process(a.asInstanceOf[A])
     ...
   }
   ...
}

(未经测试!)

假设您可以更改发送消息的代码,我可以建议使用以下设计吗? MessageProcessor现在是一个类型类,因此您可以添加任意数量的消息类型。通过发送闭包作为消息,您可以将任意数量的上下文走私到呼叫站点。

class MessageReceiver extends Actor {
  def receive = {
    case fn: Function0[Unit] =>
      fn()
  }
}

trait MessageProcessor[A] {
  val dest: ActorSelection
   def process(a: A): A
}

object Processors {

  implicit object StringProcessor extends MessageProcessor[String] {
    val dest: ActorSelection = Wellknown.stringDest
    def process(a: String): String = a + "1"
  }

  implicit object IntProcessor extends MessageProcessor[Int] {
    val dest: ActorSelection = Wellknown.intDest
    def process(a: Int): Int = a + 1
  }

  def sendMessage[A](msg: A)(implicit ev:[MessageProcessor[A]]): Unit = {
    val block: Function0[Unit] = { () =>
      ev.dest ! ev.process(msg)
    }

    val msgDest = system.actorOf[Props[MessageReceiver]], "msgDest")
    msgDest ! block
  }
}

(也未经过测试!)