Это дизайнерское решение является прекрасным примером того, как Ruby объединяет парадигмы объектно-ориентированного и функционального программирования. Это очень мощная функция, которая может создавать простой читаемый код.
Это помогает понять, что происходит. Когда вы запускаете:
array.each do |el|
#some code
end
вы вызываете метод each
объекта array
, который, если верить имени переменной, является экземпляром класса Array
. Вы передаете блок кода этому методу (блок эквивалентен функции). Затем метод может оценить этот блок и передать аргументы, используя block.call(args)
или yield args
. each
просто перебирает массив и для каждого элемента вызывает блок, который вы передали с этим элементом в качестве аргумента.
Если бы each
был единственным методом использования блоков, это было бы не так полезно, как многие другие методы, и вы даже можете создать свой собственный. Например, в массивах есть несколько методов итераторов, включая map
, который делает то же самое, что и каждый, но возвращает новый массив, содержащий возвращаемые значения блока, и select
, который возвращает новый массив, который содержит только элементы старого массива. для которого блок возвращает истинное значение. Подобные вещи было бы утомительно делать с использованием традиционных методов зацикливания.
Вот пример того, как вы можете создать свой собственный метод с блоком. Давайте создадим метод every
, который будет немного похож на карту, но только для каждого n элементов в массиве.
class Array #extending the built in Array class
def every n, &block #&block causes the block that is passed in to be stored in the 'block' variable. If no block is passed in, block is set to nil
i = 0
arr = []
while i < self.length
arr << ( block.nil? ? self[i] : block.call(self[i]) )#use the plain value if no block is given
i += n
end
arr
end
end
Этот код позволит нам выполнить следующее:
[1,2,3,4,5,6,7,8].every(2) #= [1,3,5,7] #called without a block
[1,2,3,4,5,6,7,8,9,10].every(3) {|el| el + 1 } #= [2,5,8,11] #called with a block
Блоки допускают выразительный синтаксис (часто называемый внутренними DSL), например, веб-микрофрейм Sinatra.
Синатра использует методы с блоками для краткого определения http-взаимодействия.
например.
get '/account/:account' do |account|
#code to serve of a page for this account
end
Этой простоты было бы трудно достичь без блоков Руби.
Надеюсь, это позволило вам увидеть, насколько мощна эта языковая функция.