Ruby中的“yield”关键字是什么作用?

38

我遇到了以下Ruby代码:

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

each方法是什么?特别是,我不理解yield的作用。

8个回答

36

这是一个扩展你示例代码的示例:

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上,迭代器已经超出了数组的末尾。这是不使用块的潜在陷阱,因为如果您不知道数组中有多少元素,您可能会请求太多的项目并获得异常。

使用带有块的each将遍历@items接收者,并在到达最后一个项目时停止,避免了错误,使代码保持简洁明了。


你是不是指的是这里所述的Begin-End块?我对Ruby还很陌生,所以想弄清楚你在那里所说的块是什么意思。 - Am33d
#each 中,您还会看到 return to_enum(:each) unless block_given?,当没有给出块时,它将返回一个 Enumerator,从而允许像 collection.each.take(10) 这样的操作。 - Kris

17

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

例如,each可以在数组类中实现如下:

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

10

一个 Ruby 方法通过调用 yield 关键字来调用代码块。它可用于遍历列表,但不像其他某些语言中的迭代器。

这里有一个很好的解释,它比我能做到的更好地解释了它。


2
就我个人而言,我发现这个页面对于{code}yield{code}的解释更为简单易懂。 - JoeyC

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

我被yield名称12调用

将调用id为14的yield

我被yield名称14调用

yield是如何工作的?

因此,当name函数在任何地方运行时,无论yield出现在哪个位置,代码块都会运行。也就是说,name {|i| puts "I am called by yield name #{i}"}

您可以看到有一个单词yield 12,它运行块内的代码并将12作为i的值传递。

这里是一个游戏示例:

def load_game
    puts "Loading"

    yield

end


load_game { puts "Game loaded" }

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

加载中

游戏已加载


6
作为新手,我看了许多答案后仍然感到困惑,直到看到Abhi的回答。
yield命令暂停执行方法中的代码,并将控制权传递回调用它的代码块,执行该代码块,然后继续执行其余的方法。以下是一个例子,可以帮助理解:
def hello
    puts "hello"
    yield 
    puts "world"
end

hello do
    puts "there"
end 

输出:

你好

在那里

世界


5

yield告诉Ruby调用传递给方法的块,并将其参数传递给它。

如果方法没有使用块被调用,则yield会产生错误,而return语句不会产生错误。

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


4

这样做的效果是,在 MyClass 的实例上调用 .each 方法,与在该实例的 .items 上调用 .each 方法相同。


3
< p > cpm说它正在获取该块并执行它 < /p > < p > 简单示例: < /p >
def my_method
  yield
end


my_method do
  puts "Testing yield"
end

Testing yield
=> nil 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接