Как выдать пустой генератор?
У меня есть метод, который берет генератор плюс некоторые дополнительные параметры и выдает новый генератор:
function merge(\Generator $carry, array $additional)
{
foreach ( $carry as $item ) {
yield $item;
}
foreach ( $additional as $item ) {
yield $item;
}
}
Обычный вариант использования этой функции похож на этот:
function source()
{
for ( $i = 0; $i < 3; $i++ ) {
yield $i;
}
}
foreach ( merge(source(), [4, 5]) as $item ) {
var_dump($item);
}
Но проблема в том, что иногда мне нужно передать пустой источник merge
метод. В идеале я хотел бы иметь возможность сделать что-то вроде этого:
merge(\Generator::getEmpty(), [4, 5]);
Что именно так, как я бы сделал в C# (есть IEnumerable<T>.Empty
имущество). Но я не вижу никаких empty
Генератор в руководстве.
Мне удалось обойти это (пока) с помощью этой функции:
function sourceEmpty()
{
if ( false ) {
yield;
}
}
И это работает. Код:
foreach ( merge(sourceEmpty(), [4, 5]) as $item ) {
var_dump($item);
}
правильно выводит:
int(4)
int(5)
Но это, очевидно, не идеальное решение. Каков будет правильный способ передачи пустого генератора в merge
метод?
3 ответа
Я нашел решение:
поскольку \Generator
продолжается \Iterator
Я могу просто изменить подпись метода на это:
function merge(\Iterator $carry, array $additional)
{
// ...
Это входная ковариация, поэтому она нарушит обратную совместимость, но только если кто-то расширит merge
метод. Любые вызовы все равно будут работать.
Теперь я могу вызвать метод с родным PHP EmtpyIterator
:
merge(new \EmptyIterator, [4, 5]);
И обычный генератор тоже работает:
merge(source(), [4, 5])
Немного опоздал, но сам нуждался в пустом генераторе и понял, что создать его на самом деле довольно легко...
function empty_generator(): Generator
{
yield from [];
}
Не знаю, лучше ли это, чем использовать EmptyIterator
, но таким образом вы получите точно такой же тип, как и непустые генераторы, по крайней мере.
Просто для полноты, возможно, наименее подробный ответ до сих пор:
function generator() {
return; yield;
}
Я только задавался вопросом об этом же вопросе и вспомнил раннее описание в документах (которое должно быть по крайней мере семантически до сегодняшнего дня), что функция генератора - это любая функция с yield
ключевое слово.
Теперь, когда функция вернется до того, как выйдет, генератор должен быть пустым.
И так оно и есть.
Пример на 3v4l.org: https://3v4l.org/iqaIY
Как объясняется в официальных документах, вы можете создать Generator
Например, с помощью yield
в выражении:
$empty = (yield);
Это должно работать, но когда я попытался использовать это, я получил фатальную ошибку (yield
выражение может быть использовано только в функции). С помощью null
тоже не помогло:
$empty = (yield null); //error
Так что я думаю, что вы застряли с sourceEmpty
функция... это было единственное, что я нашел, что работает... обратите внимание, что это создаст null
значение в массиве, который вы перебираете.
Весь код был протестирован на PHP 5.5.9, кстати
Лучшее исправление, которое я могу придумать (учитывая, что совместимость является проблемой), было бы сделать оба аргумента необязательными:
function merge(\Generator $carry = null, array $additional = array())
{
if ($carry)
foreach ($carry as $item)
yield $item;
foreach ($additional as $item)
yield $item;
}
foreach(merge(null, [1,2]) as $item)
var_dump($item);
Таким образом, существующий код не будет тормозить, и вместо создания пустого генератора, передача null
тоже будет работать нормально.