如何传递一个空的生成器参数?

问题描述 投票:14回答:4

我有一个使用生成器加上一些附加参数并返回一个新生成器的方法:

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生成器in the manual

我已经设法使用此功能解决此问题:

function sourceEmpty()
{
    if ( false ) {
        yield;
    }
}

这可行。代码:

foreach ( merge(sourceEmpty(), [4, 5]) as $item ) {
    var_dump($item);
}

正确输出:

int(4)
int(5)

但是这显然不是理想的解决方案。将空生成器传递给merge方法的正确方法是什么?

php language-design yield language-details
4个回答
18
投票
有点晚,但是我自己需要一个空的生成器,并且意识到创建一个生成器实际上很容易...

function empty_generator(): Generator { yield from []; }

不知道这是否比使用EmptyIterator更好,但是通过这种方式,至少可以得到与非空生成器完全相同的类型。

4
投票
我已经找到解决方法:

由于\Generator扩展了\Iterator,所以我只能将方法签名更改为此:

function merge(\Iterator $carry, array $additional) { // ...

这是输入协方差,因此它

将破坏了向后兼容性,但前提是有人确实扩展了merge方法。任何调用仍然有效。

现在我可以使用PHP的本机EmtpyIterator调用该方法:

merge(new \EmptyIterator, [4, 5]);

并且通常的生成器也可以工作:

merge(source(), [4, 5])


4
投票
出于完整性考虑,也许是迄今为止最不冗长的答案:

function generator() { return; yield; }

[我只是想知道相同的问题,并且想起了文档中的早期描述(至少应该在语义上直到今天),生成器函数是任何带有yield关键字的函数。

现在,当函数在屈服之前返回时,生成器应该为空。

就是这样。

[3v4l.org上的示例:https://3v4l.org/iqaIY


1
投票
the official docs中所述,您可以通过在表达式中使用Generator来创建嵌入式yield实例:

$empty = (yield);

应该起作用,但是当我尝试使用它时,出现了致命错误(yield表达式只能在函数中使用)。使用null也无济于事:

$empty = (yield null); //error
所以我想您对sourceEmpty函数感到困惑...这是我发现唯一可行的方法...请注意,它

will在您要创建的数组中创建一个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也将很好地工作。
© www.soinside.com 2019 - 2024. All rights reserved.