“闭包”是如何使用它实现对象系统和基本控制结构的强大抽象?

时间:2011-03-16 11:36:55

标签: scala groovy closures

以下是programming scala第1章的引用:

  

闭包是一种强大的抽象,对象系统和基本控制结构通常使用它们来实现

显然,该声明并非专门针对Scala,而是关于闭包,但我不能 从中学到很多东西。也许它只是那些强大的编译器作者的智慧之珠!

那么谁使用Closures实现基本控制结构?为什么?

编辑:我记得在groovy中使用闭包作为方法调用的最后一个参数的语法阅读有关自定义控件结构的内容,并使用元类或{{使结构​​可用于您的代码1}} Categories的关键字。它可能是相关的吗?

编辑:我找到了groovy自定义控件结构语法here的以下参考(幻灯片38):

  

自定义控制结构

     

感谢关闭

     
      
  • 当封闭是最后一次时,它们可以被放在括号中“。”   周围参数
  •   
  • use
  •   
  • unless(account.balance > 100.euros, { account.debit 100.euros })
  •   
  • 签名unless(account.balance > 100.euros) { account.debit 100.euros }
  •   

显然,groovy提供的是一种语法糖,用于使基于Closure的自定义控制结构看起来像语言本身提供的一流控制结构。

4 个答案:

答案 0 :(得分:7)

我评论了控制结构的情况。让我评论闭包作为对象。考虑在对象上调用方法时会发生什么;它不仅可以访问参数列表,还可以访问对象的字段。也就是说,方法/函数关闭字段。这与关闭范围中的变量的“裸”函数(即,不是对象方法)没有什么不同。但是,对象语法提供了一个很好的抽象和模块化机制。

例如,我可以写

case class Welcome(message: String) {
  def greet(name: String) = println(message + ", " + name)
}
val w = Welcome("Hello")
w.greet("Dean")

VS

val message = "Hello"
val greet = (name: String) => println(message + ", " + name)
greet("Dean")

实际上,在这个示例中,我可以从Welcome中删除“case”关键字,因此该消息不会成为字段,但该值仍在范围内:

class Welcome2(message: String) {    // removed "case"
  def greet(name: String) = println(message + ", " + name)
}
val w = new Welcome2("Hello")        // added "new"
w.greet("Dean")

它仍然有效!现在greet关闭输入参数的值,而不是字段。

var welcome = "Hello"
val w2 = new Welcome2(welcome)
w2.greet("Dean")     // => "Hello, Dean"
welcome = "Guten tag"
w2.greet("Dean")     // => "Hello, Dean"  (even though "welcome" changed)

但是如果类直接引用外部作用域中的变量,

class Welcome3 {                  // removed "message"
  def greet(name: String) = println(welcome + ", " + name) // reference "welcome"
}
val w3 = new Welcome3
w3.greet("Dean")                  // => "Guten tag, Dean"
welcome = "Buon giorno"
w3.greet("Dean")                  // => "Buon giorno, Dean"

有意义吗?

答案 1 :(得分:3)

有三种基本控制结构:

序列

a = 1
b = 2
c = a + b

条件

if (a != b) {
  c = a + b
} else {
  c = a - b
}

迭代/环

for (a <- array) {
  println(a)
}

所以,我猜他们的意思是内部许多语言都使用闭包来控制结构(你可以看看最后两个结构)。

举个例子:

if (a < b) {
  for (i = a; a < b; a++) {
    println(i)
    c = i * i
  }
} else {
  c = a - b
}

所以forif闭包内的闭包,else也是闭包。这就是我理解它的方式。如果条件为真,它们会为第一个if创建一个闭包,在大括号内创建闭包,调用它。然后为for循环创建一个闭包,并在条件为真时调用它。

我想没有内部使用闭包的语言列表。

更新

举个例子,这就是你如何在Scala中实现自己的for循环(o是西里尔文,所以它会编译):

def fоr(start: Unit, condition: => Boolean, increment: => Unit)(body: => Unit): Unit = {
  if (condition) {
    body
    increment
    fоr(0, condition, increment)(body)
  }
}

var i = 0

fоr (i = 0, i < 1000, i += 1) {
  print(i + " ")
}

实际上,这就是如何在内层实现其他语言。

答案 2 :(得分:1)

我会说“闭包是如此强大的抽象...... ”,因为与标准方法不同,你有一个对调用对象的引用,无论调用闭包的范围如何

例如,在Groovy中,您可以添加一个新方法,“大写”为String类型:

String.metaClass.capitalize = {  
    delegate[0].upper() + delegate[1..-1].lower()  
}   
"hello".capitalize() // "Hello"

或者,您可以执行更复杂的操作,例如使用闭包创建特定于域的语言(DSL)。

class ClosureProps {

       Map props = [:]  
       ClosureProps(Closure c) {  
           c.delegate = this // pass closure scope to "this"
           c.each{"$it"()} // iterate through closure, triggering missingMethod()
       }  
       def methodMissing(String name, args) {  
           props[name] = args.collect{it} // collect extracted closure properties
       }  
       def propertyMissing(String name) {  
           name  
       }  
}  

示例

class Team {

        // the closure
        static schema = {  
            table team  
            id teamID  
            roster column:playerID, cascade:[update,delete]  
        }  
}  
def c = new ClosureProps(Team.schema)  
println c.props.id // prints "teamID"

答案 3 :(得分:-5)

a)在提问之前,请至少尝试使用Google搜索主题。

b)完成后,请提出具体问题。

c)词法闭包是可以访问在调用它们时不可用的词汇环境的函数。因此,它们的参数可用于选择消息,并使用这些消息传递参数。对于一般控制结构,它们是不够的,除非它们以连续的方式影响调用堆栈。