Proc.new绑定更改和循环逻辑抽象

时间:2017-11-14 13:07:14

标签: ruby

我在两种不同的方法中有两个循环,看起来非常相似。我想在Proc.new

中抽象出大多数逻辑

此作品

def matches_base?
  proc_exec = Proc.new do |subclass, breakpoint|
    # next and return are meant to act inside the loop and quit it if needed
    response = process_match(subclass)
    next if response == :continue
    return true if response == false

    return response
  end

  subclasses(BASE_NAMESPACE).each do |subclass|
    proc_exec.call(subclass)
  end
  false
end

这里显而易见的问题是proc_exec是在方法本身内部定义的,但我想在另一种方法中使用它

def matches_breakpoints?
  breakpoints.fetch.each do |breakpoint|
    # I want to include the proc_exec here too
  end
  false
end

所以我只是尝试在类级别提取它

这不起作用

def proc_exec
  Proc.new do |subclass, breakpoint|
    response = process_match(subclass)
    next if response == :continue
    return true if response == false

    return response
  end
end

def matches_base?
  subclasses(BASE_NAMESPACE).each do |subclass|
    proc_exec.call(subclass)
  end
  false
end

然后我可以在两个实例方法中调用proc_exec.call。目前它抛出

 LocalJumpError:
   unexpected return

我尝试了很多技巧,例如instance_evalinstance_exec但没有成功。我现在没有解决方案了。

易于执行,简化我想要的示例。

class MyLoops
  def proc_exec
    Proc.new do |num|
      next if num == 1
      # we want this `return` to act in the method context
      # as it would do if I defined it inside a method directly
      return if num == 4
      puts "Current number : #{num}"
    end
  end

  def method_a
    [0,1,2].each do |num|
      proc_exec.call(num)
    end
    false
  end

  def method_b
    [3,4,5].each do |num|
      proc_exec.call(num)
    end
  end
  # this `false` below should never be reached ; that's the trick
  false
end

loops = MyLoops.new
loops.method_a
loops.method_b

1 个答案:

答案 0 :(得分:1)

你不能吃蛋糕也不能吃。如果你希望proc中的return中止该方法,它必须在方法的词法范围*中(这是另一种说法“它必须在同一方法中定义”)。

另一种方法是让proc / lambda返回一个“stop”值,调用者将使用该值来中止其执行。

(遗憾的是,你对instance_eval / instance_exec的实验误导了。这些方法只改变当前的self。这个问题与当前的self无关,而是当前的词法范围,其中return 1}}被执行。)

*您收到的错误,原因是return尝试从不再运行的方法(proc_exec)返回。