我想知道是否可以将块传递给Proc。简单地将块传递给Proc.call
不起作用:
foo = Proc.new {
yield
}
foo.call {
puts "test"
}
结果:
LocalJumpError:没有给定块(yield)
lambdas也是如此。但是 可以使用方法对象:
class Foo
def bar
yield
end
end
bar = Foo.new.method :bar
bar.call { puts "Success!" }
结果:
成功!
奇怪的是,在将方法对象转换为proc之后仍然有效:
bar.to_proc.call { puts "Success!" }
结果:
成功!
那么为什么从一个块生成的Proc不接受块,但原来是一个方法的Proc呢?是否可以从接受块的块创建Procs?
答案 0 :(得分:5)
Procs不能接受块作为隐式参数(您正在尝试的格式)。 proc 可以接收其他proc对象作为参数,显式或使用&参数。例如:
a = Proc.new do |&block|
block.call
end
a.call() {puts "hi"}
yield
是一种语言级别的魔法,只能在方法的上下文中使用。
答案 1 :(得分:0)
以上答案并非100%正确,因此无法接受。尤其是零件;
Procs不能接受块作为隐式参数(您正在尝试的格式)。 proc可以显式地或使用&参数接收其他proc对象作为参数。
这是错误的。 Procs和Lambda可以在自己的体内调用yield
。要记住的事实是Proc/lambda bodies have a lexical scope
!这意味着,如果在定义Proc / lambda时存在一个块,yield
将成功执行,就像这样;
def foo
my_proc = Proc.new { yield }
my_proc.call
end
foo { puts "Hello world!" } # would print "Hello world!"
如您所见,yield
发挥了作用!因为在定义Proc时存在障碍。
可以说,Proc在调用时展开为具有阻塞的方法,因此yield
起作用。这也是错误的,可以使用以下代码片段轻松地予以反驳;
def foo
@my_proc ||= Proc.new { yield }
@my_proc.call
end
foo { puts "Hello again!" } # would print "Hello world!"
foo # would print "Hello world!"
正如您再次看到的,它与在定义Proc时具有块有关。
如果您想更好地理解在词法范围内的含义,让我们来看下面的示例。
class Foo
def self.hello_proc
Proc.new { puts name }
end
def self.name
"Alice"
end
end
class Bar
def self.put_name
Foo.hello_proc.call
end
def self.name
"Bob"
end
end
Bar.put_name # would print "Alice"
您可以将以上代码复制并粘贴到irb会话中,以查看输出结果。它之所以加上“ Alice”,是因为在定义Proc时,名称是“ Alice”。