这是关于Akka Cookbook第10章" Enveloping actor"的一个问题。有人可以解释为什么我们不能只是通过"标题"作为参数起作用,但必须将其作为"标题_"在创建envelopingActor?
package com.packt.chapter10
import java.util.UUID
import akka.actor.{Actor, ActorRef, ActorLogging, ActorSystem, Props}
import Envelope._
object Envelope {
type Headers = Map[String, Any]
case class Envelope[T](msg: T, headers: Headers = Map.empty)
}
class EnvelopingActor(nextActor: ActorRef, addHeaders: Any => Headers) extends Actor {
def this(nextActor: ActorRef) =
this(nextActor, _ => Map())
override def receive: Receive = {
case msg => nextActor ! new Envelope(msg, addHeaders(msg))
}
}
class EnvelopeReceiver extends Actor with ActorLogging {
override def receive: Receive = {
case x => log.info(s"Received [$x]")
}
}
object EnvelopingActorApp extends App {
val actorSystem = ActorSystem()
val envelopeReceiver = actorSystem.actorOf(Props[EnvelopeReceiver], "receiver")
val envelopingActor = actorSystem.actorOf(
Props(classOf[EnvelopingActor], envelopeReceiver, headers _))
envelopingActor ! "Hello!"
def headers(msg: Any) = Map(
"t" -> System.currentTimeMillis(),
"cId" -> UUID.randomUUID().toString
)
}
答案 0 :(得分:3)
如果您尝试删除_
,则可能会看到如下错误:
错误:(379,59)缺少对象EnvelopingActorApp中方法头的参数列表
当应用函数类型时,未应用的方法仅转换为函数。
您可以通过编写headers _
或headers(_)
代替headers
来明确转换此内容。
问题是Props
是任何一组actor参数的通用容器。特别是它事先并不知道将有多少参数。所以它使用以下签名:
def apply(clazz: Class[_], args: Any*): Props
您可能会发现args
的类型为Any*
。这个*
意味着参数的数量是可变的,并且每个参数都是Scala中可用的最通用类型 - Any
,它不是函数类型。
至于为什么Scala编译器在这种情况下不会自动将方法转换为函数类型 - 我认为答案是类型安全。想象一下,然后在某些时候你有headers
没有参数(所以headers
实际上是一个方法的调用),后来你修改它以获取一个参数。由于Any
匹配任何类型,编译器无法注意到这实际上是一个重大变化(您已经将就地调用更改为仅传递可能稍后调用的函数)。如果参数是强类型的某种函数类型,编译器可以注意到差异,因此可以安全地自动进行转换。