Оператор yield

Оператор yield используется в функциях, генерирующих последовательности, и имеет вид:

yield выражение

Функция, содержащая yieldы, называется итератором. При каждом вызове такая функция выполняет код до следующего yieldа, после чего заканчивает свою работу, возвращая значение выражения, указанного в yieldе, и сохраняет своё состояние до следующего вызова.

Например:

function Squares(n: integer): sequence of integer;
begin
  for var i:=1 to n do
    yield i*i
end;

begin
  var q := Squares(5);

  foreach var x in q do
    Print(x);
  Println;

  q.Println;
end.

В данном примере переменная q хранит последовательность, т.е. алгоритм вычисления квадратов первых n чисел, который будет запущен либо в цикле foreach по последовательности q, либо вызовом метода расширения Println для последовательности q. Данные последовательности поочередно возвращаются вызовами оператора yield в теле функции Squares.

После каждого вызова оперматора yield функция возвращает следующее значение i*i, заканчивает свою работу и сохраняет значения всех своих переменных во внутреннем контексте. При следующем вызове этой функции её тело как бы начинает выполняться с той точки, в которой мы оказались в конце предыдущего вызова.

В выражении yield могут фигурировать внешние относительно функции переменные. Говорят, что оператор yield осуществляет захват таких переменных. Например:

var a := 2;

function Squares(n: integer): sequence of integer;
begin
  for var i:=1 to n do
    yield i*a
end;

begin
  var q := Squares(5);

  q.Println;
  a := 3;
  q.Println;
end.

В данном коде оператор yield захватывает переменную a из внешнего контекста. Захват производится по ссылке: если изменить переменную a в основной программе и повторно вызвать функцию-итератор, то при генерации последовательности будет использовано измененное значение переменной a. В итоге вывод данной программы будет иметь вид:

2 4 6 8 10
3 6 9 12 15

Для функций, в теле которых присутствуют yield, имеется ряд ограничений:

  1. Функции, содержащие yield, могут возвращать только последовательности.
  2. Среди параметров функций-итераторов не может быть const, var, params-параметров и параметров по умолчанию.
  3. Если функция использует yield, в ней запрещено использовать переменную Result, и наоборот.
  4. Функции с yield не могут содержать операторы lock, try...except, try..finally.
  5. Yield не может быть вложена в оператор with.
  6. Yield не может быть использована внутри лямбда-выражений.
  7. Функции с yield не могут содержать вложенные подпрограммы и сами быть вложенными подпрограммами.
  8. Функции с yield не могут содержать локальные определения типов
  9. Методы расширения с yield не могут быть рекурсивными.