我看到的大多数例子都是微不足道的,我不确定这会增加什么语言。我明白为什么你会在Objective-C中使用块来处理回调,或者在Javascript中使用闭包作为定时器的回调,但是我不确定我在Ruby中使用块是什么。它可以用来代替inject
之类的函数吗?
答案 0 :(得分:2)
Ruby全面使用块,它是该语言中最普遍的功能之一。它基本上是函数作为值的优化案例。一个真正的函数对象,就像在JavaScript中一样,是一个Proc
类的实例。一个块不一个对象,从而避免了对象所产生的一些开销。原因是,在几乎所有你想要传递一个函数作为参数的情况下,你只会传递一个,你会想要在那里定义它,所以为什么不优化,并使事情成为一个在语法上更好吗?
这是一个块:
[1, 2, 3].each do |i|
puts i
end
这是一个功能:
func = Proc.new do |i|
puts i
end
[1, 2, 3].hypothetical_each(func)
你可以看到,即使定义一个功能值也需要一个块(作为Proc
构造函数的参数)。
您通常在inject
中使用某个块,而不是函数。你几乎在Ruby中的每个循环结构中都使用它(while
非常罕见)。
您还可以使用块来构建像Sinatra这样的特定于域的语言:
get 'index.html' do
"Hello World"
end
或Rspec:
describe "addition" do
it "should add two numbers together" do
(1+2).should equal(3)
end
end
很好地学习块,因为如果没有它们,你就无法阅读,也不能很好地编写Ruby。
答案 1 :(得分:0)
红宝石中的块的秘密与红宝石的设计本质有关。
Ruby使用对象模式设计,其中方法调用作为“消息”发送到对象,返回值是响应。在ruby中(与python和其他一些语言不同),函数和方法本身并不是对象。 块是ruby在这种模式中允许类似函数的消息的方式,并且是ruby处理迭代的关键。
如果我错了,请有人纠正我,但我相信在没有创建块或使用while语句的情况下实际上不可能在ruby中进行任何迭代
事实上,for i in object
表示法只是访问对象each
方法的语法简写。
即
for i in 1..5
#do stuff with i
end
执行完全相同:
1..5.each do |i|
#do stuff with i
end
通过ruby VM,其中Range对象1..5
(包括ruby标准库Enumerable模块)将它的元素传递给传递的块
在幕后,这个操作看起来像这样(注意这是一个简化的版本,没有考虑到...独家和..包含版本的范围)
class Range
def init(start, end)
@start = start
@end = end
end
def each
i = @start
while i < @end
yield i
i += 1
end
end
end
因此,当调用for循环时,它会创建一个范围对象obj = Range.new(1,5)
,然后向对象obj.send(:each, &block)
发送一条消息,并在每个方法内部使用while循环并生成块
<强> TL; DR 强>
Ruby在内部使用块,因为它们对它的设计至关重要,没有它们,语言本身就无法使用它的message => object => response
模态。
所以你不应该问:“我为什么要用积木?”因为没有它们就无法编写ruby程序。
相反,您应该问:“ruby中的块与Objective-C和Javascript中的块有何不同?”因为他们是不同的。
我不能说Objective-C,但在JavaScript中,块是一个非常重要的对象。它是代码的容器,其他对象可以拾取并用于执行任何需要的操作,块甚至不必与使用它的对象相关联。
在ruby中,一个块更像是一个对象在它自己使用的邮件中接收的一组指令(然后它会在下次出现时传递给邮件人)