Ruby:块内的收益率

时间:2014-06-11 07:03:17

标签: ruby return yield

以下是扫描示例:

"abcdeabcabc".scan("a")

所以它返回一个3 a的数组。另一个扫描示例:

"abcdeabcabc".scan("a") {|x| puts x}

只输出每个“a”,但仍然输出一个数组,这次它实际上是它返回的原始字符串。

因此,从上面的文档和行为中,扫描要么返回一个数组(没有给出块),要么返回原始字符串,在此之前会发生一些副作用。关键是这两种情况都会返回一些东西。

那么如果我在块内放一个“收益”会发生什么?什么将被退回?或者,没有? 返回值的类型是什么?

"abcdeabcabc".scan("a") {|x| yield x}

以上内容不起作用,因为Ruby抱怨没有给出阻止。这对我来说很有意义。但如果它是类方法的一部分,比如说,自我实现的“每个”,则以下工作:

class Test
  def my_each
    "abcdeabcabc".scan("a") {|x| yield x}
  end
end
# => :my_each

t = Test.new
# => #<Test:0x007ff00a8d79b0>

t.my_each {|x| puts "so this is #{x}"}
# it works. Outpus 3 a's then return the original string.

那么,Test类的my_each方法的返回值是多少?这是收益率列表还是什么?但正如之前所讨论的“abcdeabcabc”.scan(“a”){| x |在给出一个块之前,Ruby会抱怨yield x}段。内部发生了什么事情,将my_each的块提供给my_each实现中的段?

3 个答案:

答案 0 :(得分:2)

该块与该函数的参数类似地传递。这可以明确指定,如下所示:

class Test
  def my_each(&block)
    "abcdeabcabc".scan("a") do |x|
      puts "!!! block"
      yield x
      # Could be replaced with: block.call(x)
    end
  end
end

从技术上讲,它完全相同(puts放在那里进行澄清),它的存在不会像通常对参数那样进行检查。如果你忘记给它一个块,函数将停止在它必须以完全相同的yield执行的第一个LocalJumpError(至少,这是我在Rubinius上得到的)。但是,请注意控制台中的“!!! block”。

这样做是有原因的。您可以使用if block检查您的函数是否被赋予块,如果是如上所述,使用yield,然后跳过content_tag。一个很好的例子是Rails的content_tag :div do content_tag :div end 帮助器。这个助手的调用可以是块嵌套的。一个简单的例子:

<div>
  <div></div>
</div>

...产生如下输出:

yield

因此,该块在您的方法的“顶部”(就调用堆栈而言)执行。每次Enumerator发生时都会调用它作为块上的某种函数调用。之后执行该块时,它不会累积在任何地方。

UPD:

许多each es返回的my_each由许多迭代器显式构造,以保存应该发生的事件的上下文。

可以在class Test def my_each(&block) if block "abcdeabcabc".scan("a") { |x| yield x } else Enumerator.new(self, :my_each) end end end

上实现
{{1}}

答案 1 :(得分:1)

由于块被赋予scan,因此返回原始字符串。在块内做什么并不重要。

答案 2 :(得分:0)

"abcdeabcabc".scan("a") {|x| yield x}

在上述情况下,#scan每个匹配的字符传递给与其关联的块

现在在#scan的块中,您正在调用yield,然后调用传递给方法my_each的块。 x的值将传递给您通过方法my_each调用传递的块。

这太简单了,没有混淆。

  

Test类的my_each方法的返回值是什么?

根据您当前的代码,返回值应该是#scan方法返回值,这又会导致最后一个语句的结果与调用方法#my_each的方法#scan(如果被调用)或接收器相关联的块。

  

这是一份收益清单还是什么?

是的,yield将被调用,因为#scan方法可以找到多个匹配项。

考虑以下示例: -

"abcdeabcabc".scan("w") {|x| yield x}

此处与方法#scan相关联的将不会被调用,因为#scan找不到任何匹配项,这就是为什么yield不会也被调用,因此方法#my_each不会输出块表达式(与方法一起传递)结果,但是"abcdeabcabc"