代码之家  ›  专栏  ›  技术社区  ›  Daniel Vandersluis

从给定给实例_exec的块中提前返回

  •  3
  • Daniel Vandersluis  · 技术社区  · 15 年前

    我需要允许在类的范围内使用 instance_exec (通过Rails 2.3.2)。然而,在某些情况下,其中一些块需要提前返回,这给我带来了一个问题。

    LocalJumpError (意外返回)在1.8.7中:

    class Foo
      def square(n)
        n ** 2
      end
    
      def cube(n)
        n ** 3
      end
    
      def call_block(*args, &block)
        instance_exec *args, &block
      end
    end
    
    block = lambda { |n|
      return square(n) if n < 5
      cube(n)
    }
    
    f = Foo.new
    f.call_block(5, &block) # returns 125
    f.call_block(3, &block) # returns 9 in 1.8.6, throws a LocalJumpError in 1.8.7
    

    return 在我的街区 next 但是 next square(n) if n < 5 导致 nil 在1.8.6中。

    我有没有办法让它在1.8.6和1.8.7中都工作?我知道我可以重新构造我的块以使用分支而不是提前返回,但是有些块更复杂,并且有多种需要提前返回的情况。

    编辑: 我发现它在1.8.6而不是1.8.7中工作的原因是1.8.7定义了它自己的 实例执行 在C源代码中,而1.8.6使用Rails的实现。如果我覆盖 实例执行 在Rails版本的1.8.7中,它也可以在那里工作。

    1 回复  |  直到 10 年前
        1
  •  1
  •   coreypurcell    15 年前

    看到这个了吗 post

    class Foo
    
      def square(n)
        n ** 2
      end
    
      def cube(n)
        n ** 3
      end
    
      def call_block(*args, &block)
          instance_exec *args, &block
        end
    end
    
    
    
    
    def a
      block = lambda { | n|
        return square(n) if n < 5
        cube(n)
      }
     f = Foo.new 
    puts f.call_block(3, &block) # returns 125
    puts "Never makes it here in 1.8.7"
    puts f.call_block(5, &block) # returns 9 in 1.8.6, returns nothing in 1.8.7
    end
    
    a
    

    进程和lambda的工作方式在1.9中发生了变化。这有助于解释发生了什么。

    起初的

    class Foo
    
      def square(n)
        n ** 2
      end
    
      def cube(n)
        n ** 3
      end
    
      def call_block(*args, &block)
        block.call(self, *args)
      end
    end
    
    block = lambda { |obj, n|
      return obj.square(n) if n < 5
      obj.cube(n)
    }
    
    f = Foo.new
    puts f.call_block(5, &block) # returns 125
    puts f.call_block(3, &block) # returns 9
    

    post