当你调用一个函数时,实际上是在调用该函数的apply方法。换句话说,假设有以下代码:
def doImport(fileImportID: Int, filename: String) {
println(s"Importing file #$fileImportID ($filename)")
}
以下代码片段:
val f = doImport _
f(123, "file.txt")
...只是语法糖,实际上等同于:
val f = doImport _
f.apply(123, "file.txt")
如果在使用命名参数进行调用时,编译器会查找参数名称的位置,那肯定就是在
apply
方法的定义中。
事实证明,对于
Function2
,这些参数的名称分别为
v1
和
v2
。所以我们可以这样做:
scala> f.apply(v1=123, v2="file.txt")
Importing file
现在让我们看看当使用语法糖(也就是删除对apply
的显式调用)时,它是否仍然有效:
scala> f(v1=123, v2="file.txt")
Importing file
很好,它工作了。
现在当然,v1
和v2
不完全等同于fileImportID
和filename
,但我们可以通过一些类型细化来修复它:
type ImportFunc = ((Int, String)=>Unit) {
def apply(fileImportID: Int, filename: String): Unit
}
基本上这只是一个 (Int, String)=>Unit
(或者换句话说是 Function2[Int, String, Unit]
),但带有重新定义 apply
和我们所需的参数名称。让我们看到它的作用:
scala> val f: ImportFunc = doImport _
f: ImportFunc = <function2>
scala> f(fileImportID=123, filename="file.txt")
Importing file #123 (file.txt)
成功!
一个重要的侧面说明:就打字而言,ImportFunc
与 Function2[Int, String, Unit]
或任何其他类似的细化是相同的。
这是因为参数名称不是签名的一部分。所以在我的例子中,f
仍然可以传递到期望 Function2[Int, String, Unit]
的任何地方
(但从那时起,您将无法再使用自定义参数名称调用它)。