Ruby迭代器产量

时间:2016-07-08 07:35:25

标签: ruby iterator block yield

我想知道为什么以下标记方法会产生不同的结果:

方法1:

def tag(html)
  print "<#{html}>#{yield}</#{html}>"
end

方法2:

def tag(html)
  print "<#{html}>"
  print yield
  print "</#{html}>"
end

当我使用上述方法在终端中运行以下代码时:

tag(:ul) do
  tag(:li) { "It sparkles!" }
  tag(:li) { "It shines!" }
  tag(:li) { "It mesmerizes!" }
end

第一个给了我:

<li>It sparkles!</li><li>It shines!</li><li>It mesmerizes!</li><ul></ul>

第二个给了我:

<ul><li>It sparkles!</li><li>It shines!</li><li>It mesmerizes!</li></ul>

第二个是我正在寻找的输出。

第一种方法如何打印&#39;产生&#39;在它打印之前发生的事情&#39; yield&#39;在字符串?

2 个答案:

答案 0 :(得分:1)

主要问题是操作顺序。当您致电print时,它会立即打印 ,没有延迟,这可能会导致问题。

在Ruby中,处理返回字符串的代码通常更容易,而不是导致打印等副作用的代码。如果它们返回字符串,则可以控制输出的位置。如果他们立即打印出来,你需要非常小心你打电话给他们的订单。

您使用tag(:ul)调用在最终程序集中调用该代码的方式实际上会遇到麻烦。你的方法的第二个版本巧合地订购了正确的东西。

解决这个问题并不一定容易。如果返回一个字符串,则只会使用三个tag调用中的最后一个字符串。如果你打印,你必须确保你使用第二种方法使它工作。

在Rails系统中,有一种方法可以捕获这些东西的输出以用于缓冲目的,但这是一个非常麻烦的尝试和做法,当你尝试处理所有情况时它会变得非常混乱。

在可能的情况下创建某些缓冲区,这些东西可以写入,然后当所有内容都用print或其他任何内容写出来时。

答案 1 :(得分:1)

回应@ tadman的回答:评估的顺序和api的不一致。您的块有时会返回字符串,有时会将字符串作为副作用打印出来。

  print "<#{html}>"
  print yield
  print "</#{html}>"

在这里打印,然后屈服。如果块返回一个字符串(:li块之一),那么它就打印在这里。如果它是:ul块,那么会产生副作用(打印li块),之后会打印出nil。

在另一种情况下

print "<#{html}>#{yield}</#{html}>"

Ruby必须组装一个字符串才能打印。这意味着在任何印刷之前屈服。这意味着在打印开头<ul>之前,会发生副作用。由于ul块返回nil,这就是为什么它在字符串末尾打印为空(<ul></ul>)。

有意义吗?