Оператор 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, имеется ряд ограничений:
- Функции, содержащие yield, могут возвращать только последовательности.
- Среди параметров функций-итераторов не может быть const, var, params-параметров и параметров по умолчанию.
- Если функция использует yield, в ней запрещено использовать переменную Result, и наоборот.
- Функции с yield не могут содержать операторы lock, try...except, try..finally.
- Yield не может быть вложена в оператор with.
- Yield не может быть использована внутри лямбда-выражений.
- Функции с yield не могут содержать вложенные подпрограммы и сами быть вложенными подпрограммами.
- Функции с yield не могут содержать локальные определения типов
- Методы расширения с yield не могут быть рекурсивными.