什么时候在Ruby中使用Procs?

时间:2013-06-30 01:10:57

标签: ruby

我已经阅读了几本关于Ruby的书籍,我理解了如何创建和调用Procs。但这些书中的例子都是人为的,而且是微不足道的。我想知道什么时候使用Proc而不是使用传统的方法做同样的事情实际上有用吗?也许有人可以发布一个非平凡的例子?

2 个答案:

答案 0 :(得分:1)

在Ruby中,Proc是存储稍后要在对象中运行的一些代码的好方法。块不是对象,但可以很容易地转换为Procs。 Procs对许多事情很有用。过程通常用于实现callbacks。我最近在编写系统模拟时使用了Procs。每次我在模拟中调用step方法时,我都希望发生各种各样的事情。我不希望模拟对象本身知道有关这些事情的细节;我只是想让它调用我定义的回调。我可以通过定义一堆自定义类或对象来完成相同的事情,每个自定义类或对象都有call方法,但使用Procs肯定更简单。

class X
  def initialize
    @step_callbacks = []
  end

  def every_step(&proc)
    # If you print proc.class here, you can see it is a Proc
    @step_callbacks << proc
  end

  def step
    # ...perform the step...
    @step_callbacks.each do |proc|
      proc.call
    end
  end
end

x = X.new

x.every_step do
  # check some assertions about the state of the simulation
end

x.every_step do
  # update a related simulation
end

x.step
x.step

我希望你不要认为这个例子是人为的。我确实用它来完成我的工作。此外,我使用相同的模式来处理我的Minecraft机器人as you can see here中收到的数据包。

当你想让一些对象调用某些代码但你不希望它确切知道它调用的代码时,回调非常有用。 Proc是一种实现回调的简单方法。

答案 1 :(得分:0)

Proc是一个对象,因此您可以创建包含它们的复杂对象。例如,您可以创建一个与指令键匹配的哈希:

object1 = {
  :foo => ->{execute_foo_routine},
  :bar => ->{execute_bar_routine},
  ...
}
...
object1[:foo].call # => execution

请注意,所有信息都包含在object1中。当您想要封装所有必要信息并使其独立于外部代码时,这非常有用。 object1是可移植的。

如果你想使用方法做到这一点,那么并非所有信息都可以放在对象中,但是需要在其他地方定义方法:

object2 = {
  :foo => :foo_routine,
  :bar => :bar_routine,
  ...
}

def foo_routine
  ...
end
def bar_routine
  ...
end
...
send(object2[:foo]) # => execution

object2不像object1那样便携。