【问题标题】:What is the ruby equivalent of Go defer?Go defer 的 ruby​​ 等价物是什么?
【发布时间】:2016-06-15 07:21:27
【问题描述】:

我是 Ruby 的新手,我正在做一个涉及使用它的项目。 Go 提供了 defer 语句,我想知道如何在 ruby​​ 中复制该函数。

例子:

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

【问题讨论】:

    标签: ruby go deferred


    【解决方案1】:

    在 ruby​​ 中没有与 defer 语句等效的等效项,但是如果您想确保执行特定的代码块,可以使用 ensure 语句。不同的是不能像 defer 那样堆叠代码块,但是结果是一样的。

    在一个块中

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

    在方法中

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

    Object#ensure 标记开始/结束块的最后一个可选子句, 通常在块还包含救援子句的情况下。这 ensure 子句中的代码保证被执行,无论是 控制是否流向救援块。

    【讨论】:

      【解决方案2】:

      它没有这样的声明,但你可以使用元编程来获得这种行为。

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

      【讨论】:

      • 有人对此投了反对票。为什么?这段代码不起作用吗?有不好的后果吗?这看起来合法而整洁。
      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 2022-01-20
      • 2015-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-16
      • 1970-01-01
      相关资源
      最近更新 更多