Значение слова 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 достигает урожая