Go的defer语句在Ruby中有什么等效的功能?

10

我是一个对Ruby新手,正在进行一个涉及使用它的项目。Go语言提供了defer语句,我想知道如何在Ruby中复制这个功能。

示例:

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

20

在Ruby中,没有defer语句的适当等价物,但是如果您希望确保执行特定的代码块,可以使用ensure语句。不同之处在于,您不能像defer那样堆叠代码块,但结果是相同的。

在一个块内

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

用一种方法

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

Object#ensure是一个可选的代码块最终闭合关键字,通常在该块中还包含rescue关键字。无论控制流是否转到rescue块,ensure块中的代码都保证会被执行。


11

这段代码本身没有这样的语句,但是你可以使用元编程来实现这个功能。

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

示例调用:

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

4
有人给这个帖子点了踩,为什么?这段代码不起作用吗?会有什么丑陋的后果吗?看起来很正规和整洁。 - Narfanator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接