使用`each`和`yield`来理解控制流

时间:2015-01-19 20:04:51

标签: ruby

我遇到了这段代码:

class RandomSequence
  def initialize(limit,num)
    @limit,@num = limit,num
  end
  def each
    @num.times { yield (rand * @limit).floor }
  end
end

i = -1
RandomSequence.new(10,4).each do |num|
  i = num if i < num
end

是否只调用each方法一次并计算四个不同的值,然后对于每个值,我们在doend之间执行代码块?我对控制流程的理解是否正确?

2 个答案:

答案 0 :(得分:2)

你的理解很接近。将生成随机数,然后生成块,然后生成另一个等4次。您可以通过将puts语句添加到块中来轻松验证这一点,以查看它们何时执行。

class RandomSequence
  def initialize(limit,num)
     @limit,@num = limit,num
  end

  def each
    puts "in each"
    @num.times { yield (rand.tap {|x| puts "Generated #{x}" } * @limit).floor }
  end
end

i = -1

RandomSequence.new(10,4).each do |num|
  puts "in block"
  i = num if i < num
end

输出

in each
Generated 0.6724385316643955
in block
Generated 0.8906983274750662
in block
Generated 0.49038868732214036
in block
Generated 0.38100454011243456
in block

答案 1 :(得分:1)

each类上的RandomSequence方法被调用一次。其中@num.times创建Enumerator。迭代Enumerator并调用带有yield语句的块(忽略它的参数)。

yield语句调用传递给each方法的块传递(rand * @limit).floor的值。在您的代码中,块不绑定到变量,即您可以通过执行以下操作来获取对块的引用:

def each(&block)
  #... do stuff with block, e.g. block.call("some args")
end

这有时很有用。

有点偏离主题,但有一件事我发现Ruby开始时很可怕的是return语句返回从定义它的位置执行的流程。

def create_proc
  puts "Creating proc"
  Proc.new do
    puts "In proc!"
    return "some value" # notice the explicit return
  end
end

def do_stuff
  my_proc = create_proc

  my_proc.call # This will cause a runtime error

end

如果显式return被删除,那么一切正常就没有错误......教训是,在ruby中你应该避免使用显式返回。

相关问题