10

オブジェクトが破壊されたときに何が起こるかを制御できないのは設計上のものであることはわかっています。また、一部のクラス メソッドをファイナライザーとして定義することも認識しています。

しかし、C++ の RAII (リソースはコンストラクタで初期化され、デストラクタで閉じられる) の Ruby イディオムですか? エラーや例外が発生した場合でも、オブジェクト内で使用されるリソースをどのように管理しますか?

確実に動作するようにする:

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

ただし、クラスのユーザーは、open メソッドを呼び出す必要があるたびに、 begin-rescue-ensure チャチャ全体を実行することを覚えておく必要があります。

たとえば、次のクラスがあります。

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リソースをブロックに ing するのはどうですか? 例:

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

これは、try / catch / finally のように機能するという点で、Python、Java、または C# のユーザーにはなじみがあります。

于 2008-10-18T05:49:27.493 に答える