Pull to refresh

Блоки и итераторы в Ruby

Reading time2 min
Views1.6K
Original author: Dave Thomas
Вы можете использовать блоки для реализации обратных вызовов, передачи кусков кода и для реализации итераторов.

Блоки представляют собой простые куски кода заключенные в фигурные скобки или между do… end

{ puts «Hello»} #это блок


do #
club.enroll( person) # и это тоже
person.socialize #
end #


Когда блок создан его можно ассоциировать с вызовом метода. Это делается помещением блока кода в конец строки содержащей вызов метода. Например, в следующем коде, блок, содержащий puts «Hi» ассоциирован с вызовом метода greet.
greet { puts «Hi» }

Если у метода есть параметры, они перечисляются перед блоком:
verbose_greet(«Dave», «loyal customer») {puts «Hi»}

Метод может вызвать ассоциированный блок один или несколько раз используя выражение yield. Оно похоже на вызов метода, который вызывает блок, ассоциированный с методом, содержащим yield.
Следующий пример показывает это в действии. Мы определим метод который вызывает yield два раза. Затем вызовем этот метод, поместив блок на той же линии после вызова (и после перечисления аргументов метода)
def call_block
puts «Start of method»
yield
yield
puts «End of method»
end
call_block { puts «In the block» }

результатом будет:
Start of method
In the block
In the block
End of method

Каждый вызов yield выводит на печать «In the block».
Блок кода можно вызывать с параметрами, передавая их через yield. Внутри блока просто перечислите аргументы, заключив их между вертикальными чертами (|).
def call_block
yield(«hello», 99)
end
call_block {|str, num|}


Блоки кода использеются повсюду для реализации итераторов: методы которые возвращают элементы последовательности взятые из некоторой коллекции, например, из массива.

animals = %w( ant bee cat dog elk )
animals.each {|animal| puts animal }

даст:
ant
bee
cat
dog
elk


Внутри класса Array мы бы реализовали итератор each следующим образом, используя псевдо-код:

# внутри класса Array
def each
for each element # < — псевдо код
yield element
end
end


Большинство конструкций перебора которые встроены в C или Java в Руби являются простыми методами, вызывающими ассоциированные блоки ноль или более раз.
[ 'cat', 'dog', 'horse' ].each { |name| print name, " "}
5.times { print "*" }
3.upto(6) { |i| print i }
('a'..'e').each { |char| print char }


в результате дает нам

cat dog horse *****3456abcde


Мы просим объект 5 вызвать блок пять раз и затем просим объект вызвать блок, передавая последовательные значения пока они не достигнут значения 6. И в конце диапазон величин от a до e вызывает блок используя метод each.
Все это — вольный перевод Dave Thomas — Programming ruby 2nd edition (The Pragmatic Programmers' Guide)
Tags:
Hubs:
Total votes 10: ↑8 and ↓2+6
Comments0

Articles