在互联网上的许多情况下,我看到each
了 Enumerable 方法的示例:
def each(&block)
@items.each do |item|
block.call(item)
end
end
为什么人们不使用这个:
def each(&block)
@items.each(&block)
end
有什么不同吗?
在互联网上的许多情况下,我看到each
了 Enumerable 方法的示例:
def each(&block)
@items.each do |item|
block.call(item)
end
end
为什么人们不使用这个:
def each(&block)
@items.each(&block)
end
有什么不同吗?
其实我觉得下面这个版本更常见:
def each
@items.each { |i| yield i }
end
这相当于您的第一个代码示例。但是,此版本与您的第二个版本之间存在细微差别:
class Test
def initialize(items)
@items = items
end
def each1
@items.each { |i| yield i }
end
def each2(&block)
@items.each(&block)
end
end
观察:
irb(main):053:0> Test.new([1,2,3]).each2
=> #<Enumerator: [1, 2, 3]:each>
irb(main):054:0> Test.new([1,2,3]).each1
LocalJumpError: no block given (yield)
from (irb):43:in `block in each1'
from (irb):43:in `each'
from (irb):43:in `each1'
from (irb):54
from /usr/bin/irb:12:in `<main>'
如果没有给出块,将块委托给底层迭代的版本实际上返回一个枚举器,这非常好。它允许我们写这样的东西:
irb(main):055:0> Test.new([1,2,3]).each2.map { |x| x + 1 }
=> [2, 3, 4]
为了在我们的显式版本中实现同样的效果,我们必须像这样调整它:
def each1
return enum_for(:each1) unless block_given?
@items.each { |i| yield i }
end
这更冗长。底线:尽可能将块委派给底层可枚举,以避免代码重复和此类微妙的陷阱。
顺便说一句,既然您已经意识到您的方法的双重性质each
,那么以不同的方式命名它是有意义的。例如,您可以按照String#chars
or之类的方法的示例IO#lines
调用您的方法items
:
def items(&block)
@items.each(&block)
end