Ruby中的RAII(或者,如何在Ruby中管理资源)

moo*_*ogs 10 ruby resources destructor raii finalizer

我知道你的设计是无法控制物体被摧毁时发生的事情.我也知道将一些类方法定义为终结器.

然而,C++的RAII的ruby习惯用法(资源在构造函数中初始化,在析构函数中关闭)?即使发生错误或异常,人们如何管理对象内部使用的资源?

使用确保工作:

f = File.open("testfile")
begin
  # .. process
rescue
  # .. handle error
ensure
  f.close unless f.nil?
end
Run Code Online (Sandbox Code Playgroud)

但是每次需要调用open方法时,班级用户必须记住做整个begin-rescue-ensure chacha.

例如,我将有以下课程:

class SomeResource
 def initialize(connection_string)
   @resource_handle = ...some mojo here...
 end

 def do_something()
   begin
    @resource_handle.do_that()
    ...
   rescue
    ...
   ensure
 end

 def close
  @resource_handle.close
 end

end
Run Code Online (Sandbox Code Playgroud)

如果异常是由某个其他类引起并且脚本退出,则不会关闭resource_handle.

或者更多的问题我还在做这个C++ - 比如?

Gre*_*reg 16

因此,用户不必" 记住做整个开始 - 救援 - 确保chacha "结合rescue/ ensureyield.

class SomeResource
  ...
  def SomeResource.use(*resource_args)
    # create resource
    resource = SomeResource.new(*resource_args) # pass args direct to constructor
    # export it
    yield resource
  rescue
    # known error processing
    ...
  ensure
    # close up when done even if unhandled exception thrown from block
    resource.close
  end
  ...
end
Run Code Online (Sandbox Code Playgroud)

客户端代码可以按如下方式使用它:

SomeResource.use(connection_string) do | resource |
  resource.do_something
  ... # whatever else
end
# after this point resource has been .close()d
Run Code Online (Sandbox Code Playgroud)

事实上,这就是File.open操作方式 - 让第一个答案最让人困惑(这对我的同事来说是这样).

File.open("testfile") do |f|
  # .. process - may include throwing exceptions
end
# f is guaranteed closed after this point even if exceptions are 
# thrown during processing
Run Code Online (Sandbox Code Playgroud)


bk1*_*k1e 8

如何yield将资源转换为块?例:

File.open("testfile") do |f|
  begin
    # .. process
  rescue
    # .. handle error
  end
end
Run Code Online (Sandbox Code Playgroud)