【发布时间】: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
我遇到了以下 Ruby 代码:
class MyClass
attr_accessor :items
...
def each
@items.each{|item| yield item}
end
...
end
each 方法有什么作用?特别是,我不明白yield 做了什么。
【问题讨论】:
标签: ruby yield-keyword
正如 cpm 所说,它获取块并执行它
简单示例:
def my_method
yield
end
my_method do
puts "Testing yield"
end
Testing yield
=> nil
【讨论】:
据我了解,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:
加载中
游戏加载
【讨论】:
作为一个新手,查看许多答案让我感到困惑,直到我找到了 Abhi 的答案。
yield 命令暂停执行方法中的代码,而是将控制权交还给调用它的代码块,执行该代码,然后继续执行该方法的其余部分。这是一个为我澄清的例子:
def hello
puts "hello"
yield
puts "world"
end
hello do
puts "there"
end
输出:
你好
那里
世界
【讨论】:
yield 告诉 ruby 调用传递给方法的块,并为其提供参数。
如果没有使用 return 语句不会产生错误的块调用该方法,yield 将产生错误。
return 只能发送单个值,而 Yield 返回值巨大的对象。
【讨论】:
当你编写一个接受块的方法时,你可以使用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
【讨论】:
这是一个充实您的示例代码的示例:
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 item 将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 上,迭代器从数组的末尾脱落。这是 NOT 使用块的潜在陷阱,因为如果您不知道数组中有多少元素,您可能会要求太多项目并获得异常。
将each 与块一起使用将遍历@items 接收器,并在到达最后一项时停止,从而避免错误,并使事情保持整洁。
【讨论】:
#each 中看到return to_enum(:each) unless block_given?,当没有给出允许诸如collection.each.take(10) 之类的块时,它将返回Enumerator。
最终效果是,在 MyClass 的实例上调用 .each 与在该实例的 .items 上调用 .each 相同。
【讨论】: