2

Ruby 有延续......它有dynamic-wind类似Scheme的构造吗?

4

1 回答 1

5

[这个答案是为 Scheme 程序员写的(OP 之前在这里问过其他 Scheme 问题,所以这是一个安全的选择)。如果您是因为没有 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'文件顶部。)


对于不知道 adynamic-wind是什么的读者来说,这是一种指定在退出被覆盖的代码时要运行的代码(很像ensure),以及在重新输入覆盖的代码时要运行的代码的一种方式。(当您在被覆盖的代码中使用call/cc并在被覆盖的代码退出后调用延续对象时,可能会发生这种情况。)

完全人为的例子:

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实现将确保在调用延续时$stdout将其设置回流/dev/null,以便在puts 'This should not be shown'运行的所有实例中,确实不会显示该文本。

于 2010-10-07T04:22:32.333 回答