Go defer的红宝石当量是多少?

I am a new to Ruby and I am working on a project which involves using this. Go offers the defer statement, and I wanted to know how I could replicate that function in ruby.

Example:

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

There are no proper equivalents to the defer statement in ruby, however if you want to make sure that a specific code block is executed, you can use the ensure statement. The difference is that you cannot stack code blocks like defer does, but the result is the same.

In a block

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

In a method

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

Object#ensure Marks the final, optional clause of a begin/end block, generally in cases where the block also contains a rescue clause. The code in the ensure clause is guaranteed to be executed, whether control flows to the rescue block or not.

It doesn't have such a statement, but you can use metaprogramming to get this behavior.

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

Example calls:

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>'