嵌套的yield是如何工作的?

5
我想编写一段代码,满足以下要求:
SomeClass.new.execute(method) == 3

我有:

class SomeClass
  def execute(method)
    def method
     yield
    end
  end
end

method = 1+2

我得到了nil。关于yield我仍然非常困惑。非常感谢您的任何帮助。

3个回答

5

您走在正确的方向上,但是参数method必须是代码块。

您可以通过几种不同的方式创建代码块。最常见的是匿名使用{...}do...end。如果您想将代码块存储在变量中(这是调用SomeClass.new.execute(method)所需的),则可以使用Proc.new

还有其他创建块的方法(使用lambda语法),但超出了本问题的范围。

这将使用存储在变量中的块起作用:

class SomeClass
  def execute
    yield
  end
end

method = Proc.new { 1+2 }
SomeClass.new.execute(&method) # => 3

或者更简洁地说,
SomeClass.new.execute { 1 + 2 } # => 3

1
第一个例子是不正确的。在使用yield时使用&block没有意义——yield期望一个块,而&block接受任何传入的块并将其转换为Proc,如果你正在使用yield,则这是完全不必要的。如果您要直接传递Proc而不是块,则甚至不需要&block语法,因为没有块需要包装。 - Chuck
当然,谢谢你指出来。这会教训我从(糟糕的)记忆中回答问题。已编辑。 - joews

4

你的想法有点正确。 yield 会执行传递进来的块代码。所以你需要像这样做:

class SomeClass
  def execute
    yield
  end
end

然后你可以像这样调用它:

SomeClass.new.execute { 1+2 }

4
yield关键字将控制权传递给传递给该方法的任何。你没有传递任何块,所以没有什么可以做的。
你需要像这样的东西:
class C
  def execute
    yield    # Pass control to a block that was passed in.
             # Method returns whatever the value of evaluating `b` was.
  end
end

现在您可以进行以下操作:
C.new.execute { 1 + 2 }     # Pass block containing a statement "1 + 2".
# => 3                      # The result of evaluating "1 + 2" is
                            #   returned from the #execute method.

如果您想传递与要传递的块相应的方法对象,而不是匿名指定它,您可以创建一个lambda:

b = lambda { 1 + 2 }
C.new.execute &b            # Pass an object to #execute that will be used as
# => 3                      #   the block.

Ruby有几种几乎等效的方法来创建lambda表达式:

lambda { 1 + 2 }
Proc.new { 1 + 2 }
-> { 1 + 2 }

第一个例子中的&b没有任何意义。 - Chuck
2
制作 Lambda 的方式并不等同。Proc.new {} 会创建 proc 而不是 lambda - user2422869

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接