Давайте разберем здесь код:
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
То, что у нас здесь, сводится к:
receiver.method do |block_argument_one|
# this is the _body_ of the _block_
end
Итак:
['apple', 'bad apple', 'cherry', 'durian']
называется приемник (или субъект , или просто объект или экземпляр ) eachEven
является метод , вызываемый на получателе - Все от
do
до end
является блоком. Это также может быть от {
до }
и работать одинаково (ну, в основном ) |fruit|
- список аргументов блока, с fruit
- единственным аргументом блок заботится о. puts …
это тело блока
Что происходит с блоком:
- Код в блоке получает интерпретируется, но не запускается
- Заполнитель для этого кода передается методу, к которому прикреплен блок
- , метод выполняется и может получить доступ к блоку во время выполнения
Теперь давайте посмотрим, как работает метод, который принимает блок:
class SomeClass
def some_method(regular_argument, &block_capture_argument)
# method body
# explicitly call the block:
block_capture_argument.call("first value passed to block")
# implicitly call the block (same as above)
yield "first value passed to block"
end
end
Здесь показано несколько способов использования блока:
Когда вы определяете метод с началом последнего аргумента с &
ссылка на блок становится доступной для метода по имени после &
(например, ваш аргумент wasABlock_nowAProc
). Тогда ваш метод может делать то, что ему нравится, с блоком, может вызывать его или даже хранить его где-то, и совсем другой метод может использовать его.
В качестве альтернативы, вы можете использовать ключевое слово yield
для вызова блока неявно. В этом случае вам не нужен аргумент &
для метода (но он все еще работает, если у вас есть этот аргумент). Обратите внимание, что ruby позволяет вам присоединить блок к любому методу , независимо от того, использует ли он этот блок. Методы могут проверить, был ли блок с ключевым словом block_given?
, или проверить, присутствует ли значение аргумента &
.
Когда вы вызываете блок, либо с помощью yield
, либо с call
, аргументы, которые вы передаете методу вызова, передаются в качестве аргументов блоку.
Метод может сделать с блоком все, что он хочет . Он может вызывать его один, два, 0 или 300 раз. Он может вызывать его с одинаковыми аргументами каждый раз или с разными аргументами каждый раз.
В вашем конкретном примере c блок вызывается (со значением object
) для каждого элемента в получателе , но только если переменная isEven имеет значение true.
Также в вашем конкретном примере c вы вызываете блок из другого блока (который предоставляет object
для вас), но не позволяете этому сбить вас с толку.
Подводя итог:
- блоков можно присоединить к любому методу с использованием либо
do … end
, либо {…}
- блоков не запускаются, если только метод, к которому они присоединены, не решит вызвать их
- методы будут вызваны на приемник
- методы, использующие блоки get решить, как и когда их использовать
- методы, которые используют блоки, могут вызывать блоки (или использовать
yield
) и передавать любое количество аргументов в блок. Блоки - могут быть определены для использования этих аргументов (с синтаксисом
|…|
) и могут именовать эти аргументы как угодно (важен порядок / позиция аргументов).