我对 scala curying 和按名称调用函数有点陌生。我在理解语法方面面临困难。函数的 fllow 是什么,为什么需要返回 f(result) 以及进一步应用于它的功能。
def withScan[R](table: Table, scan: Scan)(f: (Seq[Result]) => R): R = {
var resultScanner: ResultScanner = null
try {
resultScanner = table.getScanner(scan)
val it: util.Iterator[Result] = resultScanner.iterator()
val results: mutable.ArrayBuffer[Result] = ArrayBuffer()
while (it.hasNext) {
results += it.next()
}
f(results)
} finally {
if (resultScanner != null)
resultScanner.close()
}
}
让我们只看一下函数签名
def withScan[R](table: Table, scan: Scan)(f: (Seq[Result]) => R): R
首先,暂时忽略花哨的柯里语法,因为您始终可以通过将所有参数放在一个参数列表中来将柯里函数重写为普通函数,即
def withScan[R](table: Table, scan: Scan, f: Seq[Result] => R): R
其次,请注意最后一个参数本身就是一个函数,我们还不知道它的作用。withScan
会接受某人给它的功能,并将该函数用于某些事情。我们可能会对为什么有人需要这样的功能感兴趣。由于我们需要处理大量需要正确打开和关闭的资源,例如文件,数据库连接,套接字,...然后,我们将重复关闭资源的代码,或者更糟糕的是,忘记关闭资源。因此,我们希望将无聊的通用代码排除在外,为您提供一个方便的功能:如果您使用withScan
访问表,我们将以某种方式为您提供Result
,以便您可以处理它,并且我们将确保为您正确关闭资源,以便您可以专注于有趣的操作。这就是所谓的"贷款模式">
现在让我们回到柯里格式法。虽然 currying 还有其他有趣的用例,但我相信它以这种风格编写的原因是用 Scala 编写的,您可以使用大括号块将参数传递给函数,即可以像这样使用上面的函数
withScan(myTable, myScan) { results =>
//do whatever you want with the results
}
这看起来就像一个内置的控制流,如 if-else 或 for 循环!
据我了解,这是需要一些Table
(可能是数据库表)并尝试使用参数scan
scna此表的功能。使用相关scanner
收集数据后,此方法只需将收集的序列映射到类型为R
的对象。 对于此类映射,它f
函数使用。
您可以使用此功能:
val list: List[Result] = withScan(table, scanner)(results => results.toList)
或
val list: List[Result] = withScan(table, scanner)(results => ObjectWhichKeepAllData(results))
恕我直言,它写得不是很好的代码,而且我觉得最好是在这个函数之外做映射的事情。让客户端进行映射(BTW 应该为每个结果进行映射),并仅对该功能进行扫描。
这是一个高阶函数的例子:一个将另一个函数作为参数的函数。
该函数似乎执行以下操作: - 使用传入扫描程序打开传入的表 - 使用迭代器解析表,在本地 ArrayBuffer 中填充条目 - 调用由调用方传入的函数,用于已解析的条目序列。
函数参数允许此函数用于对扫描信息执行任何操作,具体取决于传入的函数。
函数原型同样可以声明:
def withScan[R](table: Table, scan: Scan, f: (Seq[Result]) => R): R = {
该函数已使用两个参数列表声明;这是柯里的一个示例。 这在调用函数时是一个好处,因为它允许使用更清晰的语法调用该方法。
考虑一个可能传递到此函数中的函数:
def getHighestValueEntry(results: Seq[Result]): R = {
如果没有柯里,该函数将像这样调用:
withScan[R](table, scan, results => getHighestValueEntry(results))
使用柯里化,可以以一种使函数参数更清晰地突出的方式调用函数。 这得益于 Scala 中如果您只传入一个参数,则能够使用大括号而不是括号将参数括起来:
withScan(table, scan) { results =>
getHighestValueEntry(results) }