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

标签 scala akka

这是一个关于 Akka Cookbook 第 10 章“Enveloping actor”菜谱的问题。有人可以解释一下为什么我们不能只将“headers”函数作为参数传递,而必须在创建 envelopingActor 时将其作为“headers _”传递吗?

原始代码可以在这里找到: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
  )
}

最佳答案

如果您尝试删除 _,您可能会看到如下错误:

Error:(379, 59) missing argument list for method headers in object EnvelopingActorApp
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing headers _ or headers(_) instead of headers.

问题是,Props 是任何 Actor 参数集的通用容器。特别是它事先不知道会有多少个参数。所以它使用以下签名:

def apply(clazz: Class[_], args: Any*): Props 

您可能会看到 args 的类型为 Any*。此 * 意味着参数数量是可变的,并且每个参数都是 Scala 中可用的最通用类型 - Any,它不是函数类型。

至于为什么 Scala 编译器在这种情况下不会自动将方法转换为函数类型 - 我认为答案是类型安全。想象一下,然后在某个时刻,您的 headers 不带任何参数(因此 headers 实际上是对该方法的调用),后来您将其修改为带一个参数。由于 Any 匹配任何类型,编译器无法注意到这实际上是一个重大更改(您已将就地调用更改为仅传递稍后可能调用的函数)。如果参数是某种函数类型的强类型,编译器可以注意到差异,从而可以安全地自动进行转换。

关于scala - 为什么在这种情况下不能将函数名称作为参数传递?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47746602/

相关文章:

java - 如何上传和解析csv文件

mysql - 使用 slick 在 Play Framework 中创建一个 MySQL 连接

scala - 设置 IntelliJ 2017 以使用 Gradle 4.2 和最新的 Play Framework 2.6

scala - 如何将函数的返回类型指定为(任意)monad?

scala - 如何使用相同的案例类创建多个数据框

scala - akka:查询监护人 Actor 的 child

scala - 如何在 spark-xml 中禁用科学记数法

scala - 映射失败的 Future 的异常

akka - 带有异步处理程序的 Websocket

java - 如何在scala akka中找到父 Actor