【问题标题】:Ruby default block and yieldRuby 默认块和产量
【发布时间】:2017-01-01 08:34:00
【问题描述】:

我正在解决以下问题:

describe "some silly block functions" do
  describe "reverser" do
    it "reverses the string returned by the default block" do
      result = reverser do
        "hello"
      end

      expect(result).to eq("olleh")
    end

据我了解,这应该反转一个字符串。我的代码如下:

def reverser
    yield "hello"
end

reverser do |i|
    puts i.reverse
end

这只是返回“你好”。我可能在这里遗漏了一些关于产量、块和函数如何相互作用的基本概念。我该如何去做我想要完成的事情?

【问题讨论】:

    标签: ruby string methods block yield


    【解决方案1】:

    我知道已经有一年了,但还没有得到正确的回答。

    def reverser
      out = []
      yield.split.each{|word| out << word.reverse}
      out.join(" ")
    end
    

    我很确定这与范围有关

    【讨论】:

      【解决方案2】:

      我同意上述回复 - 它们是最有意义的。但想补充一下为什么您的代码无法正常工作以及如何修复它:

      expect(result).to eq("olleh")

      因此,根据您希望结果返回一个字符串。是这样做的吗?

      1. puts 返回零。当您在方法的末尾放置时 - 请注意该方法将返回 nil。这是阴险的,因为有时结果不是预期的。
      2. 但您希望它返回“olleh”
      3. 摆脱看跌期权,它应该可以按预期工作(未经测试)
      def reverser
        yield "hello"
      end
      
      reverser do |i|
        i.reverse  # NOTE THAT THE PUTS is missing here
      end
      

      我认为这就是您要寻找的。

      编辑:请测试并告诉我,因为有些人认为我的答案完全错误!当然,您不想依赖您用作设计点的特定块,但这应该让您了解它为什么不起作用

      【讨论】:

      • 以特定方式执行一次函数并不会永久改变其行为。这是一个错误的答案,你和提问的人落入了同一个陷阱。
      • @tadman - 谢谢 - 你能详细说明一下吗?当我在 ruby​​(不是 rspec)中对其进行测试时,它返回了我的预期。消除 puts 消除了问题,因为它会导致错误。
      • 您已经定义了一个返回"hello"reverser 函数,然后您执行它一次,由于您发送它的块,执行该操作。这会产生正确的输出,但会倒退优先级:reverser 方法应该反转字符串,块应该提供要反转的字符串。
      【解决方案3】:

      答案是好的和正确的,但也许它仍然没有帮助。

      你应该从你的规范开始:

      它“反转默认块返回的字符串”

      所以,很清楚你的方法应该做什么:

      def reverser
        # should reverse the string returned by the default block
      end
      

      现在让我们看看如何实现它。好的,它应该扭转一些事情。但是什么?让我们看看:

      默认块返回的字符串

      这表明我们需要执行默认块并获取其返回值。让我们看看docs 怎么说:

      yield - 从方法体内部调用,将控制权交给作为方法调用的一部分提供的代码块(如果有)。 ... 调用 yield 的值就是执行的代码块的值。

      所以,您的方法似乎需要执行yield。它将执行一个块并返回块返回的值。因此,只需在此处输入 yield

      def reverser
        yield
      end
      

      如果你运行你的规范,它会报错——你会看到字符串仍然没有反转。所以,这就是你的方法要做的事情:

      def reverser
        yield.reverse
      end
      

      就是这样。

      【讨论】:

      • 那么什么是默认块?如果没有提供块,那么 yield 语句的实际行为如何?它会代替变量吗?
      • 我将“默认块”理解为未分配给局部变量的块,而不是在调用方法时未提供任何块时的某种预定义块。所以,你打电话给yield
      【解决方案4】:

      如果你想把要反转的字符串放在block中,那么你需要得到block的调用结果并反转它。

      def reverser(&block)
        block.call.reverse
      end
      
      irb(main):009:0> result = reverser do
      irb(main):010:1*   "hello"
      irb(main):011:1> end
      => "olleh"
      

      【讨论】:

      • 在这里声明块是多余的,过于冗长和混乱。 yield 存在是有原因的。
      • 我试图给 OP 一个他能理解的答案。对于刚被屏蔽的人来说,明确的性质更容易理解。
      • 最好先解释一下这些事情,然后再向人们抛出一个奇怪而陌生的符号,比如&amp; 如何捕获块。
      【解决方案5】:

      您需要在reverser 中包含反转字符串的逻辑。

      def reverser
        yield.reverse
      end
      

      但是为什么还要麻烦使用块呢?使用普通参数会更清晰。

      def reverser(str)
        str.reverse
      end
      
      reverser('hello')  #=> olleh
      

      【讨论】:

      • 使用块的原因有很多,但能够推迟对参数的评估就是其中之一。将其更改为采用常规参数会破坏本练习的目的。
      猜你喜欢
      • 2012-03-29
      • 2011-03-05
      • 2014-08-01
      • 2015-03-01
      • 1970-01-01
      • 2011-01-01
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多