【问题标题】:What does the "yield" keyword do in Ruby?Ruby 中的“yield”关键字有什么作用?
【发布时间】:2011-05-18 07:54:27
【问题描述】:

我遇到了以下 Ruby 代码:

class MyClass
    attr_accessor :items
    ...
    def each
        @items.each{|item| yield item}
    end
    ...
end

each 方法有什么作用?特别是,我不明白yield 做了什么。

【问题讨论】:

    标签: ruby yield-keyword


    【解决方案1】:

    正如 cpm 所说,它获取块并执行它

    简单示例:

    def my_method
      yield
    end
    
    
    my_method do
      puts "Testing yield"
    end
    
    Testing yield
    => nil 
    

    【讨论】:

      【解决方案2】:

      接收代码块的 Ruby 方法通过使用 yield 关键字调用它来调用它。它可用于迭代列表,但它不像您在其他一些其他语言中找到的那样是迭代器。

      Here 是一个很好的解释,比我能解释的更好。

      【讨论】:

      • fwiw - 我发现 this page 专门对 {code}yield{code} 进行了更简单的解释
      【解决方案3】:

      据我了解,yield 从块中执行代码。

      def name
          puts "A yield will be called with id of 12"
          yield 12
          puts "A yield will be called with id of 14"
          yield 14
      end
      
      
      name {|i| puts "I am called by yield name #{i}"}
      

      输出:

      将调用 id 为 12 的 yield

      我的名字叫yield 12

      将调用 id 为 14 的 yield

      我的名字叫yield 14

      产量如何运作?

      因此,当 name 函数运行时,无论 yield 出现在哪里,块代码都会运行。这是name {|i| puts "I am called by yield name #{i}"}

      你可以看到有一个词yield 12yield运行块内的代码传递12作为i的值。

      这是一个游戏示例:

      def load_game
          puts "Loading"
      
          yield
      
      end
      
      
      load_game { puts "Game loaded" }
      

      这将在打印loading 之后立即打印game loaded

      加载中

      游戏加载

      【讨论】:

        【解决方案4】:

        作为一个新手,查看许多答案让我感到困惑,直到我找到了 Abhi 的答案。

        yield 命令暂停执行方法中的代码,而是将控制权交还给调用它的代码块,执行该代码,然后继续执行该方法的其余部分。这是一个为我澄清的例子:

        def hello
            puts "hello"
            yield 
            puts "world"
        end
        
        hello do
            puts "there"
        end 
        

        输出:

        你好

        那里

        世界

        【讨论】:

          【解决方案5】:

          yield 告诉 ruby​​ 调用传递给方法的块,并为其提供参数。

          如果没有使用 return 语句不会产生错误的块调用该方法,yield 将产生错误。

          return 只能发送单个值,而 Yield 返回值巨大的对象。

          【讨论】:

            【解决方案6】:

            当你编写一个接受块的方法时,你可以使用yield关键字来执行块。

            例如,each 可以像这样在 Array 类中实现:

            class Array
              def each
                i = 0
                while i < self.size
                  yield( self[i] )
                  i = i + 1
                end
              end
            end
            

            MyClass#each 占用一个块。它为实例的 items 数组中的每个项目执行一次该块,并将当前项目作为参数传递。

            可以这样使用:

            instance = MyClass.new
            instance.items = [1, 2, 3, 4, 5]
            instance.each do |item|
              puts item
            end
            

            【讨论】:

              【解决方案7】:

              这是一个充实您的示例代码的示例:

              class MyClass
                attr_accessor :items
              
                def initialize(ary=[])
                  @items = ary
                end
              
                def each
                  @items.each do |item| 
                    yield item
                  end
                end
              end
              
              my_class = MyClass.new(%w[a b c d])
              my_class.each do |y|
                puts y
              end
              # >> a
              # >> b
              # >> c
              # >> d
              

              each 循环一个集合。在这种情况下,它循环遍历 @items 数组中的每个项目,在我执行 new(%w[a b c d]) 语句时初始化/创建。

              MyClass.each 方法中的yield itemitem 传递给附加到my_class.each 的块。产生的item 被分配给本地的y

              这有帮助吗?

              现在,这里有更多关于each 工作原理的信息。使用相同的类定义,下面是一些代码:

              my_class = MyClass.new(%w[a b c d])
              
              # This points to the `each` Enumerator/method of the @items array in your instance via
              #  the accessor you defined, not the method "each" you've defined.
              my_class_iterator = my_class.items.each # => #<Enumerator: ["a", "b", "c", "d"]:each>
              
              # get the next item on the array
              my_class_iterator.next # => "a"
              
              # get the next item on the array
              my_class_iterator.next # => "b"
              
              # get the next item on the array
              my_class_iterator.next # => "c"
              
              # get the next item on the array
              my_class_iterator.next # => "d"
              
              # get the next item on the array
              my_class_iterator.next # => 
              # ~> -:21:in `next': iteration reached an end (StopIteration)
              # ~>    from -:21:in `<main>'
              

              请注意,在最后一个 next 上,迭代器从数组的末尾脱落。这是 NOT 使用块的潜在陷阱,因为如果您不知道数组中有多少元素,您可能会要求太多项目并获得异常。

              each 与块一起使用将遍历@items 接收器,并在到达最后一项时停止,从而避免错误,并使事情保持整洁。

              【讨论】:

              • 您的意思是指here 所述的Begin-End Block。我是 ruby​​ 新手,所以试图找出你所说的阻塞是什么意思。
              • 您还将在#each 中看到return to_enum(:each) unless block_given?,当没有给出允许诸如collection.each.take(10) 之类的块时,它将返回Enumerator
              【解决方案8】:

              最终效果是,在 MyClass 的实例上调用 .each 与在该实例的 .items 上调用 .each 相同。

              【讨论】:

                猜你喜欢
                • 2019-09-10
                • 1970-01-01
                • 1970-01-01
                • 2012-07-01
                • 2011-01-17
                • 2014-09-27
                • 2022-11-29
                相关资源
                最近更新 更多