Scala函数Currying和call按名称函数,GenricTypes

时间:2018-03-02 14:05:36

标签: scala function currying

我对scala curying和name函数调用有点新意。我在理解语法方面遇到了困难。什么是函数的fllow为什么需要返回f(结果)以及进一步应用什么函数。

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()
    }
  }

3 个答案:

答案 0 :(得分:1)

让我们看一下函数签名

def withScan[R](table: Table, scan: Scan)(f: (Seq[Result]) => R): R

首先,忽略现在花哨的currying语法,因为你总是可以通过将所有参数放在一个参数列表中来将curried函数重写为普通函数,即

def withScan[R](table: Table, scan: Scan, f: Seq[Result] => R): R

其次,注意最后一个参数是一个函数,我们不知道它到底做了什么。 withScan将采用某人提供的函数并在某些事物上使用该函数。我们可能会对为什么有人需要这样的功能感兴趣。由于我们需要处理大量需要正确打开和关闭的资源,例如File,DatabaseConnection,Socket,......然后我们将重复使用关闭资源的代码,甚至更糟糕的是,忘记关闭资源。因此,我们希望将无聊的公共代码考虑在内以便为您提供方便的功能:如果您使用withScan访问该表,我们将以某种方式为您提供Result,以便您可以对此进行操作我们将确保为您正确关闭资源,以便您可以专注于有趣的操作。这称为“贷款模式”

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

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

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

答案 1 :(得分:0)

据我所知,正确的是这个函数需要一些Table(可能是db表)并尝试使用参数scan来搜索这个表格。使用相关scanner此方法收集数据后,只需将收集的序列映射到R类型的对象。 对于此类映射,使用f函数。

您可以使用此功能:

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

或者

val list: List[Result] = withScan(table, scanner)(results => ObjectWhichKeepAllData(results))
恕我直言,它编写的代码不是很好,而且我觉得更好的做法是在这个函数之外做映射。让客户端进行映射(BTW应该针对每个结果),并仅为该函数留下扫描。

答案 2 :(得分:0)

这是高阶函数的一个例子:一个将另一个函数作为参数的函数。

该功能似乎执行以下操作: - 使用传入的扫描程序打开传入的表 - 使用迭代器解析表,填充本地ArrayBuffer中的条目 - 调用由调用者传入的函数,对已解析的条目序列进行调用。

函数参数允许使用此功能对扫描的信息执行任何操作,具体取决于传入的函数。

函数原型同样可以声明:

def withScan[R](table: Table, scan: Scan, f: (Seq[Result]) => R): R = {

该函数已声明有两个参数列表;这是一个currying的例子。调用函数时这是一个好处,因为它允许使用更清晰的语法调用该方法。

考虑一个可能传递给这个函数的函数:

def getHighestValueEntry(results: Seq[Result]): R = {

如果没有curry,函数将被调用如下:

withScan[R](table, scan, results => getHighestValueEntry(results))

通过curry,可以调用函数,使函数参数更加清晰。如果你只传递一个参数,Scala能够使用花括号而不是括号来包围函数的参数,这有助于此:

withScan(table, scan) { results => 
    getHighestValueEntry(results) }