Ruby中的枚举器块执行顺序

时间:2017-01-14 18:26:40

标签: ruby

在David Black的The Well-Grounded Rubyist中,我遇到了以下关于枚举器的Ruby代码:

e = Enumerator.new do |y|
    puts "Starting up the block!"
    (1..3).each {|i| y << i }
    puts "Exiting the block!" 
end

p e.to_a

返回以下输出:

Starting up the block!
Exiting the block!
[1, 2, 3]

最让我困扰的是,我无法围绕执行的顺序。我相信输出应该更直接:

Starting up the block!
[1, 2, 3]
Exiting the block!

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:4)

e.to_a

如果要从Enumerator中创建一个数组,必须首先从中提取每个元素!

Ruby需要确保不遗漏任何内容,并且需要在返回数组之前执行整个Block。可能有另一行定义了更多元素:

Starting up the block!
Exiting the block! (Not really)
Exiting the block!
[1, 2, 3, 4, 5, 6]

输出:

p e.next
p e.next
p e.next
p e.next

替代

作为替代方案,您可以使用:

e.next

Starting up the block!
1
2
3
Exiting the block!
enum.rb:11:in `next': iteration reached an end (StopIteration)

输出:

e.each do |x|
  puts x
end

#=>
# Starting up the block!
# 1
# 2
# 3
# Exiting the block!

e.each

p e.map{ |x|
  p x
}

e.map

如果要创建数组但仍能看到正确的执行顺序,可以使用:

Starting up the block!
1
2
3
Exiting the block!
[1, 2, 3]

输出:

double a=4;
double *x=&a;
double **y=&x;
cout <<x<<endl<<(y+1)<<endl<<(y+1)[0]<<endl<<y[1];

答案 1 :(得分:1)

我会稍微重构最后一行,所以可能会更清楚一点:

e = Enumerator.new do |y|
    puts "Starting up the block!"
    (1..3).each {|i| y << i }
    puts "Exiting the block!" 
end

a = e.to_a

# At this point "Starting up the block!" and "Exiting the block!" 
# have been printed.
# Also the value of a is [1, 2, 3].

puts a # Prints [1, 2, 3]

上面的代码与您问题中的代码相同。发生了什么是枚举器不打印数组。最后一行是实际打印其值的人。

执行e.to_a时,将运行Enumerator块。它将打印开始消息,将值添加到y数组中并打印退出消息。完成后,a变量将包含[1, 2, 3],最后puts将最终打印出来。

希望这更有意义。

答案 2 :(得分:1)

你对此输出感到惊讶。

Starting up the block!
Exiting the block!
[1, 2, 3]

这很简单。评论将说明正在发生的事情。

e = Enumerator.new do |y|
    # print first message
    puts "Starting up the block!"

    # append elements to array y (but don't print it)
    (1..3).each {|i| y << i }

    # print second message
    puts "Exiting the block!" 
end

# print the array
p e.to_a

答案 3 :(得分:0)

如果你想让你的代码更加纯粹,即不使用Ruby IO / File,(Ruby IO是Ruby中所有输入和输出的基础),那么按照下面的代码中的建议尝试它会给你直截了当的输出:

e = Enumerator.new do |y|
    y << "start"
    (1..3).each {|i| y << i }
    y << "exit" 
end

p e.to_a

这将是你的输出。

# ["start", 1, 2, 3, "exit"] 

你可以试试这种方法。