10

我知道这是设计使然,您无法控制对象被销毁时会发生什么。我也知道将一些类方法定义为终结器。

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

使用确保工作:

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

但是该类的用户必须记住每次需要调用 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

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

还是更多的问题是我仍然在做这件事太像 C++?

4

4 回答 4

17

这样用户就不必“必须记住做整个 begin-rescue-ensure 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

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

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

事实上,这就是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
于 2009-07-03T04:39:20.473 回答
8

yield将资源添加到块中怎么样?例子:

File.open("testfile") do |f|
  begin
    # .. process
  rescue
    # .. handle error
  end
end
于 2008-10-18T06:09:37.390 回答
3

还是更多的问题是我仍然在做这件事太像 C++?

是的,因为在 C++ 中,资源释放隐含地发生在堆栈上的所有内容中。堆栈展开=资源销毁=调用析构函数,然后可以释放东西。由于 Ruby 没有析构函数,因此没有“在其他所有事情都完成后做”的地方,因为抓取收集可以从你所在的位置延迟几个周期。您确实有终结器,但它们被称为“处于边缘”(并非所有东西都可用)并且它们在 GC 上被调用。

因此,如果您持有一些更好地释放的资源的句柄,则需要显式释放它。确实,处理这种情况的正确习语是

def with_shmoo
  handle = allocate_shmoo
  yield(handle)
ensure
  handle.close
end
于 2010-11-29T23:30:04.417 回答
-1

http://www.rubycentral.com/pickaxe/tut_exceptions.html

在 Ruby 中,您将使用以下ensure语句:

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

这对于 Python、Java 或 C# 的用户来说很熟悉,因为它的工作方式类似于 try/catch/finally。

于 2008-10-18T05:49:27.493 回答