Ruby 方法可以访问隐式块参数吗?
Can a Ruby method access the implicit block argument?
可以使用 yield
执行传递给 Ruby 方法的隐式块参数,或者可以使用 block_given?
检查其是否存在。我正在尝试处理这个隐式块以将其传递给另一个方法。
这可能吗?
(这是对隐式块参数的访问,我正在询问。用显式参数替换它不会削减它。)
您可以对其进行 procify,更重要的是 给它一个名称,以便您可以引用它,使用 &
ampersand unary prefix sigil in the parameter list of the method,像这样:
#implicit, anonymous, cannot be referenced:
def foo
yield 23 if block_given?
end
foo {|i| puts i }
# 23
#explicit, named, can be referenced:
def bar(&blk)
yield 23 if block_given? # still works
blk.(42) if blk # but now it also has a name and is a `Proc`
# since we have the block available as an object, we can inspect it
p blk.arity, blk.parameters, blk.source_location, blk.binding
b = blk.binding
p b.local_variables.map {|var| [var, b.local_variable_get(var)] }.to_h
end
quux = "Hello"
bar { |a, b, c = nil, d: nil, &e| puts a }
# 23
# 42
# 2
# [[:opt, :a], [:opt, :b], [:opt, :c], [:key, :d], [:block, :e]]
# ["(irb)", 24]
# #<Binding:0x00007fb091051308>
# { :quux => "Hello" }
这是您的两个选择:
- 隐含的,匿名的,不是对象
- 显式,命名,
Proc
曾经有一个未记录的技巧,实际上是 Proc::new
如何在 MRI 中实现的意外副作用:Proc::new
没有检查你是否通过了一个块,它只是假设您传递了一个块并将第一个块从内部 VM 堆栈的顶部取出。因此,如果您没有将块传递给 Proc::new
,它实际上最终会为传递给该方法的隐式块创建一个 Proc
(因为那是恰好是在堆栈的顶部)。
但是,这永远无法移植,永远无法保证,永远无法在所有 Ruby 实现中发挥作用,并且 AFAIK 不再适用于 YARV。
看看this answer。在你的情况下,它会是这样的:
def outer
wrapper = lambda { |something|
p 'Do something crazy in this wrapper'
yield(something)
}
other_method(&wrapper)
end
def other_method
yield(5)
end
outer { |x| puts x + 3 }
你得到:
"Do something crazy in this wrapper"
8
=> nil
您可以通过Proc.new
引用块参数。来自文档:
::new
may be called without a block only within a method with an attached block, in which case that block is converted to the Proc
object.
示例:
def bar
yield * 2
end
def foo
bar(&Proc.new)
end
foo(123)
#=> 456
请注意 Proc.new
在不传递块的情况下调用时引发 ArgumentError
。
可以使用 yield
执行传递给 Ruby 方法的隐式块参数,或者可以使用 block_given?
检查其是否存在。我正在尝试处理这个隐式块以将其传递给另一个方法。
这可能吗?
(这是对隐式块参数的访问,我正在询问。用显式参数替换它不会削减它。)
您可以对其进行 procify,更重要的是 给它一个名称,以便您可以引用它,使用 &
ampersand unary prefix sigil in the parameter list of the method,像这样:
#implicit, anonymous, cannot be referenced:
def foo
yield 23 if block_given?
end
foo {|i| puts i }
# 23
#explicit, named, can be referenced:
def bar(&blk)
yield 23 if block_given? # still works
blk.(42) if blk # but now it also has a name and is a `Proc`
# since we have the block available as an object, we can inspect it
p blk.arity, blk.parameters, blk.source_location, blk.binding
b = blk.binding
p b.local_variables.map {|var| [var, b.local_variable_get(var)] }.to_h
end
quux = "Hello"
bar { |a, b, c = nil, d: nil, &e| puts a }
# 23
# 42
# 2
# [[:opt, :a], [:opt, :b], [:opt, :c], [:key, :d], [:block, :e]]
# ["(irb)", 24]
# #<Binding:0x00007fb091051308>
# { :quux => "Hello" }
这是您的两个选择:
- 隐含的,匿名的,不是对象
- 显式,命名,
Proc
曾经有一个未记录的技巧,实际上是 Proc::new
如何在 MRI 中实现的意外副作用:Proc::new
没有检查你是否通过了一个块,它只是假设您传递了一个块并将第一个块从内部 VM 堆栈的顶部取出。因此,如果您没有将块传递给 Proc::new
,它实际上最终会为传递给该方法的隐式块创建一个 Proc
(因为那是恰好是在堆栈的顶部)。
但是,这永远无法移植,永远无法保证,永远无法在所有 Ruby 实现中发挥作用,并且 AFAIK 不再适用于 YARV。
看看this answer。在你的情况下,它会是这样的:
def outer
wrapper = lambda { |something|
p 'Do something crazy in this wrapper'
yield(something)
}
other_method(&wrapper)
end
def other_method
yield(5)
end
outer { |x| puts x + 3 }
你得到:
"Do something crazy in this wrapper"
8
=> nil
您可以通过Proc.new
引用块参数。来自文档:
::new
may be called without a block only within a method with an attached block, in which case that block is converted to theProc
object.
示例:
def bar
yield * 2
end
def foo
bar(&Proc.new)
end
foo(123)
#=> 456
请注意 Proc.new
在不传递块的情况下调用时引发 ArgumentError
。