我遇到了以下Ruby代码:
class MyClass
attr_accessor :items
...
def each
@items.each{|item| yield item}
end
...
end
each
方法是什么?特别是,我不理解yield
的作用。
我遇到了以下Ruby代码:
class MyClass
attr_accessor :items
...
def each
@items.each{|item| yield item}
end
...
end
each
方法是什么?特别是,我不理解yield
的作用。
这是一个扩展你示例代码的示例:
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
上,迭代器已经超出了数组的末尾。这是不使用块的潜在陷阱,因为如果您不知道数组中有多少元素,您可能会请求太多的项目并获得异常。
使用带有块的each
将遍历@items
接收者,并在到达最后一个项目时停止,避免了错误,使代码保持简洁明了。
当你编写一个带有块的方法时,可以使用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
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
:
加载中
游戏已加载
def hello
puts "hello"
yield
puts "world"
end
hello do
puts "there"
end
输出:
你好
在那里
世界
yield
告诉Ruby调用传递给方法的块,并将其参数传递给它。
如果方法没有使用块被调用,则yield
会产生错误,而return
语句不会产生错误。
return
只能发送单个值,而yield
返回大量值的对象。
这样做的效果是,在 MyClass 的实例上调用 .each 方法,与在该实例的 .items 上调用 .each 方法相同。
def my_method
yield
end
my_method do
puts "Testing yield"
end
Testing yield
=> nil
#each
中,您还会看到return to_enum(:each) unless block_given?
,当没有给出块时,它将返回一个Enumerator
,从而允许像collection.each.take(10)
这样的操作。 - Kris