Scala 函数 Currying 和按名称调用函数,GenricTypes

Scala Function Currying and call By name Functions, GenricTypes

我对 scala curing 和按名称调用函数有点陌生。我在理解语法方面遇到困难。函数的流程是什么,为什么需要返回 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()
    }
  }

据我所知,这个函数使用一些 Table(可能是 db table)并尝试使用参数 scan 扫描此表格。使用相关 scanner 收集数据后,此方法仅将收集的序列映射到 R 类型的对象。 对于这样的映射,它使用 f 函数。

您可以使用这个功能:

val list: List[Result] = withScan(table, scanner)(results => results.toList)

val list: List[Result] = withScan(table, scanner)(results => ObjectWhichKeepAllData(results))

恕我直言,代码写得不是很好,而且我觉得最好在这个函数之外做映射。让客户端进行映射(顺便说一句,每个结果都应该是映射)并只为该功能留下扫描。

我们只看函数签名

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 将采用某人提供的功能并将该功能用于某物。我们可能会对为什么有人需要这样的功能感兴趣。由于我们需要处理大量需要正确打开和关闭的资源,例如 File、DatabaseConnection、Socket 等,我们将重复关闭资源的代码,甚至更糟的是,忘记关闭资源.因此我们想把无聊的公共代码分解出来给你一个方便的功能:如果你使用withScan访问table,我们会以某种方式给你Result这样你就可以工作了在此基础上,我们将确保为您正确关闭资源,以便您可以专注于有趣的操作。这就是调用 "loan pattern"

现在让我们回到柯里化语法。尽管 currying 还有其他有趣的用例,但我相信它以这种风格编写的原因是在 Scala 中,您可以使用花括号块将参数传递给函数,即可以像这样使用上面的函数

withScan(myTable, myScan) { results =>
  //do whatever you want with the results
}

这看起来就像 if-else 或 for 循环这样的内置控制流!

这是一个 higher-order 函数的例子:一个将另一个函数作为参数的函数。

该函数似乎执行以下操作: - 使用传入的扫描仪打开传入的 table - 使用迭代器解析 table,在本地 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) }