问题严格来说是Scala语法,虽然它包含了akka的一些代码(作为示例)。
我对Scala很新。深入研究akka的源代码我想出了以下非常奇怪的方法:
def transform[C]
(f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] =
Unmarshaller.withMaterializer { implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) }
其中Unmarshaller.withMaterializer
定义为
def withMaterializer[A, B](f: ExecutionContext ⇒ Materializer => A ⇒ Future[B]): Unmarshaller[A, B]
这里发生了什么?什么是可怕的函数f: ExecutionContext => Materializer => Future[B] => Future[C]
。对我来说似乎更奇怪的是implicit
s:implicit ec => implicit mat => a => f(ec)(mat)(this(a))
的序列,尽管withMaterializer
根本没有隐含参数。
这些序列中的隐含意味着什么?
答案 0 :(得分:2)
f: ExecutionContext => Materializer => Future[B] => Future[C]
只不过是一个curried函数,因此您可以将其称为f(ec)(mat)(this(a))
,其中包含多个参数列表(从技术上讲,参数列表不属于{{1但是那些都是细节)。换句话说,def f(...)(...)
可以写成:
f
(返回函数的函数,返回另一个函数)
现在,如果您查看f: ExecutionContext => { Materializer => { Future[B] => Future[C] } }`
,则会在f(ec)(mat)(this(a))
上方定义一个电话this(a)
:
transform
(def apply(value: A)(implicit ec: ExecutionContext, materializer: Materializer): Future[B]
只是对this(a)
的调用。现在this.apply(a)
有两个隐式参数,即apply
和ec: ExecutionContext
,因此要像materializer:Materializer
一样调用它,您需要两个隐式值。这正是this(a)
定义的含义。它声明implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a))
和ec
作为所有嵌套函数体的含义,因此mat
可以选择它们。另一种可能性是写:
this(a)
答案 1 :(得分:0)
它是一个带有currying和隐含参数的lambda(应该在声明的范围内)。
"可怕"函数类型语法是currying:一个参数的函数,它接受ExecutionContext
并返回一个参数的另一个函数,它接受Materializer
并返回另一个函数,......等等。另一件事是{ {3}}。
这是一个类似结构的简单例子:
implicit val implicitInt: Int = 5
implicit val implicitString: String = "0"
val f: Int => String => String = {
implicit a => {
implicit b => {
a.toString + b
}
}
}
此处f
是一个curried函数,它接受Int
并返回一个带String
并返回String
的函数。函数值声明的一般语法是val f = { argument => ... }
,因此如果您将此参数设为隐式,则意味着范围中必须存在此类型的实例,该实例将用作默认值。您仍然可以将f
应用于某些参数:f(1)("")
,因为它仍然是一个函数。
您可以通过为每个步骤定义嵌套函数来重写您更详细询问的代码:
def transform[C](f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = {
def getExecutionContext(implicit ec: ExecutionContext): Materializer => (A => Future[B]) = {
def getMaterializer(implicit mat: Materializer): A => Future[B] = {
def applyF(a: A): Future[B] = f(ec)(mat)(this(a))
applyF // : A => Future[B]
}
getMaterializer // : Materializer => (A => Future[B])
}
Unmarshaller.withMaterializer(
getExecutionContext // : ExecutionContext => (Materializer => (A => Future[B]))
)
}