关于Scala关闭的问题(来自"Scala编程")

Ekk*_*anz 8 closures scala

我不明白为什么作者说"Scala编程"的代码清单9.1使用了闭包.在第9章中,他们展示了如何将代码重构为更复杂的形式,从这个原始代码:

object FileMatcher {
  private def filesHere = (new java.io.File(".")).listFiles
  def filesEnding(query: String) =
    for (file <- filesHere; if file.getName.endsWith(query))
      yield file
  def filesContaining(query: String) =
    for (file <- filesHere; if file.getName.contains(query))
      yield file
  def filesRegex(query: String) =
    for (file <- filesHere; if file.getName.matches(query))
      yield file
}
Run Code Online (Sandbox Code Playgroud)

到第二个版本:

object FileMatcher {
  private def filesHere = (new java.io.File(".")).listFiles
  def filesMatching(query: String,
    matcher: (String, String) => Boolean) = {
      for (file <- filesHere; if matcher(file.getName, query))
        yield file
    }    
  def filesEnding(query: String) =
    filesMatching(query, _.endsWith(_))
  def filesContaining(query: String) =
    filesMatching(query, _.contains(_))
  def filesRegex(query: String) =
    filesMatching(query, _.matches(_))
}
Run Code Online (Sandbox Code Playgroud)

他们说这里没有关闭.现在我明白了.但是他们引入了使用闭包来重构甚至更多,如代码清单9.1所示:

object FileMatcher {
  private def filesHere = (new java.io.File(".")).listFiles
  private def filesMatching(matcher: String => Boolean) =
    for (file <- filesHere; if matcher(file.getName))
      yield file
  def filesEnding(query: String) =
    filesMatching(_.endsWith(query))
  def filesContaining(query: String) =
    filesMatching(_.contains(query))
  def filesRegex(query: String) =
    filesMatching(_.matches(query))
}
Run Code Online (Sandbox Code Playgroud)

现在他们说查询是一个自由变量,但我真的不明白他们为什么这么说?由于""查询""似乎从顶部方法明确地传递到字符串匹配函数.

Eug*_*ota 17

让我们看看What is a closure中的经典add-n闭.

(define (add a)
  (lambda (b)
    (+ a b)))

(define add3 (add 3))

(add3 4) returns 7
Run Code Online (Sandbox Code Playgroud)

在上面的lambda表达式中,a自由变量,它在Wikipedia链接中定义为:

函数中引用的变量,不是局部变量或该函数的参数.upvalue是一个自由变量,它已被一个闭包绑定(关闭).

回来

def filesEnding(query: String) =
  filesMatching(_.endsWith(query))
Run Code Online (Sandbox Code Playgroud)

隐函数x => x.endsWith(query)是头等函数,其被分配给第一级的值matcher,并_.endsWith()关闭上query,类似于3关闭起来的方式a(add 3).(add3 4)相当于完成matcher(file.getName).

编辑:Tricky部分是Scala中的功能,称为占位符语法匿名函数.通过使用_代替发送者或参数,Scala自动创建一个匿名函数,我们可以将其视为lambda表达式.

例如,

_ + 1              creates       x => x + 1
_ * _              creates       (x1, x2) => x1 * x2
_.endsWith(query)  creates       x => x.endsWith(query)
Run Code Online (Sandbox Code Playgroud)

在函数内x => x.endsWith(query),query满足作为自由变量的两个要求:

  1. query 不是函数中定义的局部变量(没有局部变量).
  2. query不是函数的参数(唯一的参数是x).

  • 是的,在这段代码中"def filesEnding(query:String)= filesMatching(_.endsWith(query))"这里有一个lambda"_.endsWith(query)",当有点看起来像"{x => x.endsWith"时(查询)}".在计划符号中看起来像"(lambda(x)(endwith x query))".如您所见,在lambda"query"中是一个自由变量.它不是作为参数绑定,也不是绑定在lambda中,所以当形成闭包时,从包含环境中捕获查询,例如调用诸如"filesEnding"之类的方法. (2认同)