在这种情况下为什么不能将函数名称作为参数传递?

时间:2017-12-11 04:50:08

标签: scala akka

这是关于Akka Cookbook第10章" Enveloping actor"的一个问题。有人可以解释为什么我们不能只是通过"标题"作为参数起作用,但必须将其作为"标题_"在创建envelopingActor?

原始代码可在此处找到:https://github.com/PacktPublishing/Akka-Cookbook/tree/master/Chapter10/src/main/scala/com/packt/chapter10

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
  )
}

1 个答案:

答案 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匹配任何类型,编译器无法注意到这实际上是一个重大变化(您已经将就地调用更改为仅传递可能稍后调用的函数)。如果参数是强类型的某种函数类型,编译器可以注意到差异,因此可以安全地自动进行转换。