ndn*_*kov 5 ruby metaprogramming internals
我想知道如何将块传递给一个方法,该方法将return启用该方法yield.
天真的方法不起作用:
def run(&block)
block.call
end
run { return :foo } # => LocalJumpError
Run Code Online (Sandbox Code Playgroud)
包装在另一个proc中具有相同的效果:
def run(&block)
proc { block.call }.call
end
run { return :bar } # => LocalJumpError
Run Code Online (Sandbox Code Playgroud)
所以我认为该return声明receiver与当前的声明有关binding.然而,试一试instance_eval证明我错了:
class ProcTest
def run(&block)
puts "run: #{[binding.local_variables, binding.receiver]}"
instance_eval(&block)
end
end
pt = ProcTest.new
binding_inspector = proc { puts "proc: #{[binding.local_variables, binding.receiver]}" }
puts "main: #{[binding.local_variables, binding.receiver]}"
# => main: [[:pt, :binding_inspector], main]
binding_inspector.call
# => proc: [[:pt, :binding_inspector], main]
pt.run(&binding_inspector)
# => run: [[:block], #<ProcTest:0x007f4987b06508>]
# => proc: [[:pt, :binding_inspector], #<ProcTest:0x007f4987b06508>]
pt.run { return :baz }
# => run: [[:block], #<ProcTest:0x007f4987b06508>]
# => LocalJumpError
Run Code Online (Sandbox Code Playgroud)
所以问题是:
return语句相关联.这个连接是否可以通过语言的API访问?return块中定义块时从封闭方法返回(即创建块的闭包)。在您的示例中,没有可返回的封闭块,因此您的异常。
这很容易证明:
def foo(&block)
puts yield
puts "we won't get here"
end
def bar
foo { return "hi from the block"; puts "we never get here" }
puts "we never get here either"
end
puts bar # => "hi from the block" (only printed once; the puts in `foo` is not executed)
Run Code Online (Sandbox Code Playgroud)
在proc中返回将立即返回到proc之外,而不是从proc下的堆栈上的方法返回:
def foo(&block)
puts yield
puts "we will get here"
end
def bar
foo &->{ return "hi from the proc"; puts "we never get here" }
puts "we will get here too"
end
puts bar
# hi from the proc # puts from foo
# we will get here # puts from foo
# we will get here too # puts from bar
Run Code Online (Sandbox Code Playgroud)
由于这些行为,无法实现您所需的行为,即return给定块中的 a 将return在调用该块的方法中执行 a,除非该块是在该范围内定义的,因为这样做需要一个现有的行为不起作用。
您可以使用 throw...catch 实现类似的功能,这作为一种从任意深度压缩堆栈的方法有点有用,但您不能用它返回任意值:
def foo(&block)
yield
puts "we won't get here"
end
catch(:escape) do
foo &->{ throw :escape }
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
235 次 |
| 最近记录: |