Значение слова yield
В настоящее время я читаю "Хорошо обоснованный рубист" Дэвида А. Блэка, и я застрял в 10.9 главе (Перечислители и следующее измерение перечислимости). Мой вопрос о методе yield
.
В чем смысл слова yield
в контексте Ruby? Мой родной язык - русский, и Google Translate показывает мне множество вариантов перевода, которые меня путают. Есть некоторые из них: давать, приносить, сдаваться (сдаваться), производить, соглашаться, соблюдать и многие другие.
UPD:, пожалуйста, обратите внимание на то, что я пытаюсь понять смысл Enumerator:: Yielder #yield, но не <ключевое слово yield
.
UPD_2: Я нашел интересную статью о Enumerators: Lazy Enumerators в Ruby".
Ответы
Ответ 1
Слово yield не имеет особого значения в контексте Ruby. Это означает то же самое, что и на любом другом языке программирования, или вообще в программировании и информатике.
Обычно он используется, когда какой-то контекст выполнения передает поток управления другому сценарию выполнения. Например, в Unix существует функция sched_yield
, которую поток может использовать для отказа процессора от другого потока (или процесса). С сопрограммами термин yield
обычно используется для передачи управления от одной сопрограммы к другой. В С# существует ключевое слово yield
, которое используется методом итератора для отказа от управления методу итерации.
И на самом деле, это последнее использование точно совпадает с использованием метода Enumerator::Yielder#yield
в Ruby, о котором вы спрашивали. Вызов этого метода приостанавливает перечислитель и отказывается от управления методом перечисления.
Пример:
fibs = Enumerator.new do |y|
a, b = 0, 1
y.yield a
loop do
y.yield b
a, b = b, a + b
end
end
puts fibs.next # 0
puts fibs.next # 1
puts fibs.next # 1
puts fibs.next # 2
puts fibs.next # 3
puts fibs.next # 5
puts fibs.next # 8
puts fibs.next # 13
puts fibs.next # 21
Как видите, существует бесконечный цикл. Очевидно, что если бы этот цикл работал сам по себе, это было бы не очень полезно. Но так как каждый раз, когда он попадает в метод yield
, он отказывается от контроля до тех пор, пока он не будет вызван снова, это приведет к получению чисел Фибоначчи по одному, по существу представляя бесконечно длинный список всех чисел Фибоначчи.
Существует другой метод Fiber.yield
, который выполняет аналогичную задачу. (На самом деле, я уже описал это выше, потому что Fiber
- это просто имя Ruby для сопрограмм.) Внутри Fiber
вы вызываете Fiber.yield
, чтобы отдать управление обратно в контекст выполнения, который изначально дал вам контроль.
Наконец, существует ключевое слово yield
, которое используется внутри тела метода, чтобы передать управление блоку, который был передан в метод.
Обратите внимание, что, по крайней мере, в случае Enumerator
(т.е. в первом примере) вы можете дополнительно интерпретировать yield
как результат, так как Enumerator
создает новое значение, каждый раз при вызове yield
.
Ответ 2
В контексте уступки в Enumerator значение ближе всего к "приносите". Перечислитель вызывает метод yield своего объекта yielder, который "выдает" любое переданное ему значение.
give_me = Enumerator.new do |yielder|
(1..5).each do |n|
yielder.yield n
end
end
5.times do
p give_me.next
end
В результате:
1
2
3
4
5
В случае уступки блоку значение ближе всего к "капитуляции". Метод с оператором yield подчиняется какому-либо блоку, который вы передали этому методу.
def wage_war
p "What should I do?"
yield
end
wage_war { p "Surrender!" }
Ответ 3
@Prostosuper, связанное с ним определение, которое мне больше всего нравится, этот:
уступать, уступать, давать (сдавать; сдаться или отказаться от физическое управление другим)
В примере @Jamie Forrest, когда вызывается wage_war, "Что мне делать?" сначала печатается, затем управление потоком дается (уступается, уступает, предоставляется, передается) блоку, с которого была вызвана wage_war, в результате чего "Сдается!" печатается. После завершения этого блока управление потоком возобновляется в wage_war. Если после выхода было еще одно выражение, оно было бы выполнено, когда управление потоком возобновилось в wage_war после "Surrender!". был напечатан.
EDIT: @Prostosuper задал вопрос о выходе, поскольку он относится к Enumerators, а не к блокам, и мой пример обсуждает его использование в блоках. Вопрос SO (с ответами) об Enumerator:: Yielder # yield здесь. Смысл определения по-прежнему применяется.
Ответ 4
Вам может показаться забавным прочитать, что программирование Ruby 1.9 должно сказать о ключевом слове yield
:
Баффы на языке программирования будут рады узнать, что ключевое слово yield
выбрано для повторения урока функция в языке Liskovs CLU, язык, которому более тридцати лет, и все же содержит функции, которые все еще havent был широко использован CLU-less.
Дополнительная информация:
История CLU (pdf)
Барбара Лисков (википедия)
Ответ 5
yield, в контексте ruby "приносит":) блок передается в качестве параметра вашему методу.
def my_method
p "I have to say something:"
yield
end
my_method do
p "hello world!"
end
печатает
I have to say something:
hello world
код p "hello world" выполняется, когда my_method достигает урожая