На самом деле я думаю, что следующая версия еще более часто видела:
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
Что еще более многословным. Bottomline: Делегируйте блок в базовый перечислимый, когда это возможно, чтобы спасти себя от дублирования кода и от тонких gotchas, подобных этим.
Кстати, теперь, когда вы осознаете двусложную природу своего метода each
, имеет смысл называть его по-разному. Например, вы могли бы последовать примеру методов, как String#chars
или IO#lines
и вызове метода items
:
def items(&block)
@items.each(&block)
end
Я не уверен на 100%, так что я не буду создавать ответ, но AFAIK нет практической разницы (кроме первого, вероятно, более медленного и, безусловно, более многословного). Почему люди используют его? вероятно, потому, что это так же просто, как и в то время как второе требует некоторого понимания того, как проходить вокруг блоков/Procs. – tokland
@tokland: Это не совсем правильно, первый должен будет вернуть перечислитель, если ни один блок не будет эквивалентен второму. –
@Niklas, о, вы правы, теперь Ruby возвращает перечислитель, когда ни один блок не передается каждому. Еще одна причина использовать вторую. – tokland