Frage

Ich weiß, dass es durch Design, das Sie nicht kontrollieren können, was passiert, wenn ein Objekt zerstört wird. Ich bin mir auch bewusst eine Klassenmethode als Finalizerthread zu definieren.

Allerdings ist der Rubin Idiom für C ++ 's RAII (Ressourcen werden im Konstruktor initialisiert, in destructor geschlossen)? Wie verwalte Menschen innerhalb Objekte verwendeten Ressourcen, selbst wenn Fehler oder Ausnahmen passieren?

Mit gewährleisten funktioniert:

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

aber die Benutzer der Klasse haben sich daran zu erinnern chacha zu tun die ganze beginnen-Rettungs gewährleisten , jedes Mal die offene Methode muss aufgerufen werden.

So zum Beispiel, werde ich die folgende Klasse:

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

Die resource_handle wird nicht geschlossen werden, wenn die Ausnahme Ursache durch eine andere Klasse ist und das Skript beendet wird.

Oder ist das Problem von Ich tue dies immer noch zu C ++ - wie

War es hilfreich?

Lösung

Damit Benutzer nicht " müssen bedenken, zu tun die ganze beginnen-Rettungs gewährleisten chacha " kombinieren rescue / ensure mit yield.

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

Client-Code kann es wie folgt verwenden:

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

In der Tat ist dies, wie File.open arbeitet -. Die erste Antwort macht bestenfalls verwirrend (naja, es war zu mein Arbeitskollegen)

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

Andere Tipps

Wie wäre es, eine Ressource zu einem Block yielding? Beispiel:

File.open("testfile") do |f|
  begin
    # .. process
  rescue
    # .. handle error
  end
end
  

Oder ist das Problem von Ich tue dies immer noch zu C ++ - wie

Ja, es ist da in C ++ Ressourcen-Freigabe auf dem Stapel implizit für alles geschieht. Stapel abgewickelt = resource = Destruktoren zerstört genannt und von dort Dinge gelöst werden. Da Rubin keine Destruktoren hat es keine „tun, wenn alles andere mit getan wird“ Platz da grabage Sammlung von mehreren Zyklen verzögert werden kann, wo Sie sind. Sie haben Finalizers aber sie sind „in der Schwebe“ (nicht alles zur Verfügung, um sie) und sie erhalten aufgerufen, GC genannt.

Wenn Sie also einen Griff auf eine Ressource halten, die besser gelöst werden Sie es explizit freigeben müssen. In der Tat das richtige Idiom diese Art von Situation zu handhaben ist

def with_shmoo
  handle = allocate_shmoo
  yield(handle)
ensure
  handle.close
end

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

In Ruby, würden Sie eine ensure Anweisung verwenden:

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

Dies wird für Benutzer von Python, Java oder C # vertraut sein, dass es wie try / catch arbeitet / finally.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top