37

我遇到了以下 Ruby 代码:

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

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

4

8 回答 8

35

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

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])语句时初始化/创建。

yield itemMyClass.each方法中传递item给附加到的块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一个迭代器从数组的末尾掉了下来。这是使用块的潜在陷阱,因为如果您不知道数组中有多少元素,您可能会要求太多项目并获得异常。

使用eachwith 块将遍历@items接收器并在它到达最后一个项目时停止,避免错误,并使事情保持整洁。

于 2010-12-01T07:41:39.403 回答
17

当你编写一个接受块的方法时,你可以使用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
于 2010-12-01T08:08:59.573 回答
10

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

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

于 2010-12-01T07:42:28.780 回答
9

根据我的理解,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

我被称为产量名称 12

将调用 id 为 14 的 yield

我被称为产量名称 14

产量如何运作?

因此,当name函数在任何地方运行时,块代码都会运行。哪个是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" }

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

正在加载

游戏加载

于 2017-02-03T18:39:43.053 回答
5

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

yieldreturn如果没有使用 as语句不会产生错误的块调用该方法,则会产生错误。

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

于 2015-09-01T12:52:27.573 回答
4

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

于 2010-12-01T06:27:59.980 回答
4

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

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

def hello
    puts "hello"
    yield 
    puts "world"
end

hello do
    puts "there"
end 

输出:

你好

那里

世界

于 2016-09-11T05:47:05.890 回答
3

正如 cpm 所说的那样,它占用并执行它

简单的例子:

def my_method
  yield
end


my_method do
  puts "Testing yield"
end

Testing yield
=> nil 
于 2014-08-20T18:55:41.157 回答