如何使用命名参数在Scala中创建自定义函数类型?

Pre*_*wer 5 lambda scala

所以我想说我想创建一个名为ImportFunc的自定义函数类型,它接受一个名为fileImportID的Int和一个名为filename的字符串.我可以使用像这样的类型别名轻松地做到这一点:

type ImportFunc = (Int, String) => Unit
Run Code Online (Sandbox Code Playgroud)

问题是,任何试图使用此函数的人都不知道Int和String实际上应该是什么.有什么方法可以写出像:

type ImportFunc = (fileImportID: Int, filename: String) => Unit
Run Code Online (Sandbox Code Playgroud)

Rég*_*les 5

当你调用一个函数时,你实际上调用了该函数的 apply 方法。换句话说,考虑到:

def doImport(fileImportID: Int, filename: String) {
  println(s"Importing file #$fileImportID ($filename)")
}
Run Code Online (Sandbox Code Playgroud)

以下片段:

val f = doImport _
f(123, "file.txt")
Run Code Online (Sandbox Code Playgroud)

...只是语法糖:

val f = doImport _
f.apply(123, "file.txt")
Run Code Online (Sandbox Code Playgroud)

如果编译器在使用命名参数进行调用时会在某个地方查找参数的名称,那么这必然在apply方法的定义中。事实证明,在 中Function2,这些参数被命名为v1v2。所以我们可以这样做:

scala> f.apply(v1=123, v2="file.txt")
Importing file #123 (file.txt)
Run Code Online (Sandbox Code Playgroud)

现在让我们看看使用语法糖时它是否仍然有效(换句话说,当删除对 的显式调用时apply):

scala> f(v1=123, v2="file.txt")
Importing file #123 (file.txt)
Run Code Online (Sandbox Code Playgroud)

很好,它有效。当然,现在v1and与andv2不太一样,但我们可以通过一些类型细化来解决这个问题:fileImportIDfilename

type ImportFunc = ((Int, String)=>Unit) { 
  def apply(fileImportID: Int, filename: String): Unit 
}
Run Code Online (Sandbox Code Playgroud)

基本上这只是(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)
Run Code Online (Sandbox Code Playgroud)

成功!

重要的旁注:就打字而言,与 或任何其他类似的改进ImportFunc相同。Function2[Int, String, Unit]这是因为参数名称不是签名的一部分。因此,在我的示例中,f仍然可以将 a 传递到任何Function2[Int, String, Unit]需要 a 的地方(但从那时起,您将无法再使用自定义参数名称来调用它)。