你何时使用一个块作为传递的对象?

时间:2012-12-25 03:50:35

标签: ruby block

我看到的大多数例子都是微不足道的,我不确定这会增加什么语言。我明白为什么你会在Objective-C中使用块来处理回调,或者在Javascript中使用闭包作为定时器的回调,但是我不确定我在Ruby中使用块是什么。它可以用来代替inject之类的函数吗?

2 个答案:

答案 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中,一个块更像是一个对象在它自己使用的邮件中接收的一组指令(然后它会在下次出现时传递给邮件人)