Ruby有连续性......它是否有像Scheme这样的dynamic-wind
结构?
答案 0 :(得分:5)
[这个答案是以计划程序员的心态编写的(OP以前曾在此处提出其他方案问题,所以这是一个安全的选择)。如果你在这里因为你是一个没有Scheme背景的Ruby程序员,请阅读脚注以获取一些上下文。 : - )]
MRI没有(见下文);如果MRI没有,这意味着即使另一个实现提供它,也没有可移植的方式来使用任何此类功能。
我确实检查了MRI 1.9.1源代码。在任何情况下,这里都有一些代码来证明即使是正常的展开保护(ensure
)也不能正常使用MRI上的延续(用1.8.7和1.9.1进行测试)。 (它确实可以正常使用JRuby(我用1.5测试过),所以它表明它是一个特定于实现的东西。但请注意,JRuby只提供转义延续,而不是通用目的。)
callcc do |cc|
begin
puts 'Body'
cc.call
ensure
puts 'Ensure'
end
end
(要使用MRI 1.9+测试,您需要使用-rcontinuation
选项运行,或将require 'continuation'
放在文件的顶部。)
对于不知道dynamic-wind
是什么的读者,这是一种指定在被覆盖的代码退出时运行的代码的方法(很像ensure
),作为重新输入覆盖代码时要运行的代码。 (当您在覆盖的代码中使用call/cc
并在退出覆盖的代码后调用continuation对象时,可能会发生这种情况。)
完全做作的例子:
def dynamic_wind pre, post, &block
raise 'Replace this with a real implementation, kthx'
end
def redirect_stdout port, &block
saved = $stdout
set_port = lambda {$stdout = port}
reset_port = lambda {$stdout = saved}
dynamic_wind set_port, reset_port, &block
end
cc = nil
# cheap way to nuke all the output ;-)
File.open '/dev/null' do |null|
redirect_stdout null do
callcc {|cc|}
puts 'This should not be shown'
end
puts 'This should be shown'
cc.call
end
因此,正常运行的dynamic_wind
实现将确保在调用continuation时将$stdout
设置回/dev/null
流,以便在{{1}的所有实例中运行时,确实没有显示该文本。