RAII in Ruby (O, Come gestire le risorse in Ruby)
-
03-07-2019 - |
Domanda
So che è per progettazione che non puoi controllare cosa succede quando un oggetto viene distrutto. Sono anche a conoscenza della definizione di un metodo di classe come finalizzatore.
Comunque è il linguaggio rubino per RAII del C ++ (le risorse sono inizializzate nel costruttore, chiuse nel distruttore)? In che modo le persone gestiscono le risorse utilizzate all'interno degli oggetti anche quando si verificano errori o eccezioni?
Utilizzando assicurati che funzioni:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
ma gli utenti della classe devono ricordarsi di fare l'intero chacha inizio-salvataggio-garantire ogni volta che è necessario chiamare il metodo aperto.
Quindi, per esempio, avrò la seguente classe:
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
La risorsa_handle non verrà chiusa se l'eccezione è causata da un'altra classe e lo script esce.
O il problema è più che lo sto ancora facendo anche in C ++?
Soluzione
In modo che gli utenti non " debbano ricordare di fare l'intero chacha start-rescue-garantire " combina salvataggio
/ assicurati
con rendimento
.
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
Il codice client può usarlo come segue:
SomeResource.use(connection_string) do | resource |
resource.do_something
... # whatever else
end
# after this point resource has been .close()d
In effetti è così che funziona File.open
- rendendo la prima risposta confusa al meglio (beh, era i miei colleghi di lavoro).
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
Altri suggerimenti
Che ne dici di cedere
inging una risorsa in un blocco? Esempio:
File.open("testfile") do |f|
begin
# .. process
rescue
# .. handle error
end
end
O il problema è più che lo sto ancora facendo anche in C ++?
Sì, poiché in C ++ la deallocazione delle risorse avviene implicitamente per tutto lo stack. Stack unwound = risorse distrutte = distruttori chiamati e da lì le cose possono essere rilasciate. Dal momento che Ruby non ha distruttori, non è possibile farlo quando tutto il resto viene fatto con " luogo poiché la raccolta dei rifiuti può essere ritardata di diversi cicli da dove ti trovi. Hai dei finalizzatori ma sono chiamati " in limbo " (non tutto è disponibile per loro) e vengono chiamati su GC.
Pertanto, se si tiene un handle per alcune risorse che è meglio rilasciare, è necessario rilasciarlo esplicitamente. In effetti il ??linguaggio corretto per gestire questo tipo di situazione è
def with_shmoo
handle = allocate_shmoo
yield(handle)
ensure
handle.close
end
Vedi http://www.rubycentral.com/pickaxe/tut_exceptions.html
In Ruby, dovresti usare una accertare
istruzione:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
Questo sarà familiare agli utenti di Python, Java o C # in quanto funziona come try / catch / infine.