扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年9月30日
关键字:
在本页阅读全文(共2页)
用闭包进行定制
您已经知道如何使用现成的闭包。Ruby 让您也可以编写使用自己的闭包的方法。这种自由的形式意味着 Ruby API 的代码会更加紧凑,因为 Ruby 不需要在代码中定义每个使用模型。您可以根据需要通过闭包构建自己的抽象概念。例如,Ruby 的迭代器数量有限,但该语言没有迭代器也运行得很好,这是因为可以通过闭包在代码中构建您自己的迭代概念。
要构建一个使用闭包的函数,只需要使用 yield 关键字来调用该闭包。清单 6 是一个例子。paragraph 函数提供第一句和最后一句输出。用户可以用闭包提供额外的输出。
清单 6. 构建带有闭包的方法
def paragraph
puts "A good paragraph should have a topic sentence."
yield
puts "This generic paragraph has a topic, body, and conclusion."
end
paragraph {puts "This is the body of the paragraph."}
Results:
A good paragraph should have a topic sentence.
This is the body of the paragraph.
This generic paragraph has a topic, body, and conclusion. |
优点
通过将参数列表附加给 yield,很容易利用定制闭包中的参数,如清单 7 中所示。
清单 7. 附加参数列表
def paragraph
topic = "A good paragraph should have a topic sentence, a body, and a conclusion. "
conclusion = "This generic paragraph has all three parts."
puts topic
yield(topic, conclusion)
puts conclusion
end
t = ""
c = ""
paragraph do |topic, conclusion|
puts "This is the body of the paragraph. "
t = topic
c = conclusion
end
puts "The topic sentence was: '#{t}'"
puts "The conclusion was: '#{c}'"
|
不过,请认真操作以保证得到正确的作用域。在闭包里声明的参数的作用域是局部的。例如,清单 7 中的代码可以运行,但清单 8 中的则不行,原因是 topic 和 conclusion 变量都是局部变量:
清单 8. 错误的作用域
def paragraph
topic = "A good paragraph should have a topic sentence."
conclusion = "This generic paragraph has a topic, body, and conclusion."
puts topic
yield(topic, conclusion)
puts conclusion
end
my_topic = ""
my_conclusion = ""
paragraph do |topic, conclusion| # these are local in scope
puts "This is the body of the paragraph. "
my_typic = topic
my_conclusion = conclusion
end
puts "The topic sentence was: '#{t}'"
puts "The conclusion was: '#{c}'"
|
闭包的应用
下面是一些常用的闭包应用:
当您可以用一种简单便利的方式构建自己的闭包时,您就找到了能带来更多新可能性的技术。重构能将可以运行的代码变成运行得更好的代码。大多数 Java 程序员都会从里到外 进行重构。他们常在方法或循环的上下文中寻找重复。有了闭包,您也可以从外到里 进行重构。
用闭包进行定制会有一些惊人之处。清单 9 是 Ruby on Rails 中的一个简短例子,清单中的闭包用于为一个 HTTP 请求编写响应代码。Rails 把一个传入请求传递给控制器,该控制器生成客户机想要的数据(从技术角度讲,控制器基于客户机在 HTTP accept 头上设置的内容来呈现结果)。如果您使用闭包的话,这个概念很好理解。
清单 9. 用闭包来呈现 HTTP 结果
@person = Person.find(id)
respond_to do |wants|
wants.html { render :action => @show }
wants.xml { render :xml => @person.to_xml }
end
|
清单 9 中的代码很容易理解,您一眼就能看出这段代码是用来做什么的。如果发出请求的代码块是在请求 HTML,这段代码会执行第一个闭包;如果发出请求的代码块在请求 XML,这段代码会执行第二个闭包。您也能很容易地想象出实现的结果。wants 是一个 HTTP 请求包装程序。该代码有两个方法,即 xml 和 html,每个都使用闭包。每个方法可以基于 accept 头的内容选择性地调用其闭包,如清单 10 所示:
清单 10. 请求的实现
def xml
yield if self.accept_header == "text/xml"
end
def html
yield if self.accept_header == "text/html"
end
|
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。