我有以下类型的演员消息:
case class RetrieveEntities[A](func:(Vector[A]) => Vector[A])
然后,我想以下列方式处理该消息:
def receive = {
case RetrieveEntities(parameters, func) =>
context.become(retrieveEntities(func))
def retrieveEntities(func:(Vector[T]) => Vector[T])(implicit mf: Manifest[T]){
case _ => ...
}
我以下列方式实例化演员:
TestActorRef(new RetrieveEntitiesService[Picture])
问题是我收到以下编译器错误:
type mismatch;
[error] found : Vector[Any] => Vector[Any]
[error] required: Vector[T] => Vector[T]
[error] context.become(retrieveEntities(func))
我认为这意味着我丢失了类型信息,但我不确定为什么以及如何防止它。
答案 0 :(得分:1)
您的示例代码有点简短,无法为您提供解决方案,但从您展示的内容来看,您似乎无法做到这一点。
这就是为什么
在Scala(和Java)中,类型参数被擦除,这意味着它们在编译后会消失,因此在运行时它们不再可用。这意味着RetrieveEntities(parameters, func)
上的模式匹配实际上匹配A
可以是任何内容。然后继续调用一个用T键入的方法,编译器无法知道你的意思。
Manifest
(不推荐使用),TypeTag
和ClassTag
是一种机制,它告诉编译器创建一个对象,该对象为编译后的那些提供类型信息但是你必须&# 34;保存"那些信息。
为了能够知道你用A
输入RetrieveEntitiesService
你需要将一个隐式ClassTag带到构造函数中以使其基于任何逻辑(因为在调用构造函数时是时候你知道A是什么):
import scala.reflect.ClassTag
case class RetrieveEntities[A](func:(Vector[A]) => Vector[A])(implicit val tag: ClassTag[A])
然后,您可以在标记上调用runtimeClass以获取A:
的类型scala> val retrieve = RetrieveEntities[String](identity)
scala> retrieve.tag.runtimeClass
res2: Class[_] = class java.lang.String
请注意,由于我们现在处于运行时,因此仍然不允许您键入方法调用,但它可以让您使用该Class实例与actor的E
的runtimeClass进行比较,然后执行如果你愿意,可以安全地投射到RetrieveEntities[E]
。 (还有常规的运行时条件流,反射等)。
开始之前的两个重要注意事项
我不建议你走这条路,直到你对类型系统更有信心,真的知道没有其他合理的设计可以解决你的问题。再次,我无法帮助您使用稀疏示例代码给出这样的解决方案。 (例如,你的演员可能并不真正需要知道A
的类型,或者你可能会在具体类型上匹配一组有限的E
:
作为一个额外的警告,类型和类标签在Scala 2.10中不是线程安全的,也可能在2.11中不安全,因此将它们与actor混合可能是个坏主意。 (http://docs.scala-lang.org/overviews/reflection/thread-safety.html)
答案 1 :(得分:0)
johanandren的回答肯定是有帮助的,但最后我找到了一种可以编译的方法,现在它正在运作。
我需要为编译器提供更精确的类型注释以使其工作:
case RetrieveEntities(parameters, func:(Vector[T]) => Vector[T])
我仍然会继续使用Manifest
而不是新的Reflection API
(TypeTag
和ClassTag
),主要是因为我正在使用的库(json4s)在内部使用Manifest
实现,我认为这样可以减少问题。