【问题标题】:Can I pass a block to a Proc?我可以将块传递给 Proc 吗?
【发布时间】:2013-10-08 06:56:37
【问题描述】:

我想知道是否可以将块传递给 Proc。简单地将块传递给Proc.call 是行不通的:

foo = Proc.new {
  yield
}

foo.call {
  puts "test"
}

结果:

LocalJumpError: 没有给出块(产量)

lambda 也是如此。然而,这确实适用于方法对象:

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?

【问题讨论】:

标签: ruby


【解决方案1】:

Procs 不能接受块作为隐式参数(您正在尝试的格式)。 proc 可以接收其他 proc 对象作为参数,无论是显式的,还是使用 & 参数。示例:

a = Proc.new do |&block|
  block.call
end

a.call() {puts "hi"}

yield 是一种语言级别的魔法,只能在方法的上下文中使用。

【讨论】:

  • 你的意思是 blocks 不能接受其他块作为隐式参数?因为正如我在我的问题中所展示的那样,如果 procs 可以从方法转换为 procs。
  • @Codemonkey:我很确定 proc 也会创建一个 & 参数。
  • 我会将Proc.new do |&block| 更改为proc do |&block|,否则一个很好的答案。
【解决方案2】:

上述答案并非 100% 正确,因此不能被接受。尤其是那部分;

Procs 不能接受块作为隐式参数(您正在尝试的格式)。 proc 可以接收其他 proc 对象作为参数,无论是显式的,还是使用 & 参数。

这是错误的。 Procs 和 lambdas 可以在它们的体内调用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 起作用了。这也是错误的,可以用下面的 sn-p 很容易地反驳;

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”。

【讨论】:

  • 是的,procs 和 lambdas 可以在他们的身体里yield。但是声明 “Procs 不能接受块作为隐式参数(您正在尝试的格式)。” 并不否认这一点。只是说调用yield 不会调用您传递给proc 调用的块。 (这意味着它改为调用外部上下文的块。)
  • 我没有说它 100% 错误,我说它不是 100% 正确和误导。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 2011-07-17
  • 2017-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多