2016-06-15 4 views
4

Ich bin ein Neuling bei Ruby und arbeite an einem Projekt, bei dem ich dies verwende. Go bietet die defer-Anweisung an, und ich wollte wissen, wie ich diese Funktion in Ruby replizieren könnte.Was ist das Ruby-Äquivalent von Go Defer?

Beispiel:

dst, err := os.Create(dstName) 
if err != nil { 
    return 
} 
defer dst.Close() 

Antwort

8

Es gibt keine richtigen Mittel zur defer Aussage in Ruby, aber wenn Sie sicherstellen mögen, dass ein bestimmte Codeblock ausgeführt wird, können Sie die ensure Anweisung verwenden. Der Unterschied besteht darin, dass Sie keine Code-Blöcke wie Defer stapeln können, aber das Ergebnis ist das gleiche.

In einem Block

begin 
    # ... 
ensure 
    # This code will be executed even if an exception is thrown 
end 

Bei einem Verfahren

def foo 
    # ... 
ensure 
    # ... 
end 

Object#ensure Marks die endgültige, optional Klausel einer begin/Endblock, allgemein in Fällen, in denen die Block enthält auch eine Rettungsklausel. Der Code in der gewährleisten Klausel garantiert ausgeführt werden, ob Steuer fließt zur Rettung Block oder nicht.

0

Es hat keine solche Aussage, aber Sie können Metaprogrammierung verwenden, um dieses Verhalten zu erhalten.

module Deferable 
    def defer &block 
    @defered_methods << block 
    end 

    def self.included(mod) 
    mod.extend ClassMethods 
    end 

    module ClassMethods 
    def deferable method 
     original_method = instance_method(method) 
     define_method(method) do |*args| 
     @@defered_method_stack ||= [] 
     @@defered_method_stack << @defered_methods 
     @defered_methods = [] 
     begin 
      original_method.bind(self).(*args) 
     ensure 
      @defered_methods.each {|m| m.call } 
      @defered_methods = @@defered_method_stack.pop 
     end 
     end 
    end 
    end 
end 

class Test 
    include Deferable 

    def test 
    defer { puts "world" } 
    puts "hello" 
    end 

    def stacked_methods str 
    defer { puts "and not broken" } 
    defer { puts "at all" } 
    puts str 
    test 
    end 

    def throw_exception 
    defer { puts "will be executed even if exception is thrown" } 
    throw Exception.new 
    end 

    deferable :test 
    deferable :stacked_methods 
    deferable :throw_exception 
end 

Beispiel nennt:

t = Test.new 
t.test 

# -> Output: 
# hello 
# world 

t.stacked_methods "stacked methods" 

# -> Output: 
# stacked methods 
# hello 
# world 
# and not broken 
# at all 

t.throw_exception 
# -> Output: 
# will be executed even if exception is thrown 
# deferable.rb:45:in `throw': uncaught throw #<Exception: Exception> (UncaughtThrowError) 
#   from deferable.rb:45:in `throw_exception' 
#   from deferable.rb:18:in `call' 
#   from deferable.rb:18:in `block in deferable' 
#   from deferable.rb:59:in `<main>' 
+0

Jemand diese Downvoted. Warum? Funktioniert dieser Code nicht? Gibt es hässliche Konsequenzen? Das sieht echt und ordentlich aus. – Narfanator