如何产生空发电机?

时间:2014-08-21 14:12:18

标签: php language-design yield language-details

我有一个方法,它接受一个生成器加上一些额外的参数并产生一个新的生成器:

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方法的正确方法是什么?

4 个答案:

答案 0 :(得分:14)

迟到了,但我自己需要一个空的发电机,并且意识到创造一个实际上非常容易......

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

不知道这比使用EmptyIterator更好,但这样至少可以获得与非空生成器完全相同的类型。

答案 1 :(得分:4)

我找到了解决方案:

由于\Generator扩展\Iterator,我只需将方法签名更改为:

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

这是输入协方差,因此它破坏向后兼容性,但前提是有人确实扩展了merge方法。任何调用仍然有效。

现在我可以使用PHP的原生EmtpyIterator调用该方法:

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

通常的发电机也可以工作:

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

答案 2 :(得分:2)

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

function generator() {
    return; yield;
}

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

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

就这样。

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

答案 3 :(得分:1)

正如the official docs中所述,您可以在表达式中使用Generator创建内联yield实例:

$empty = (yield);

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

$empty = (yield null); //error

所以我猜你坚持使用sourceEmpty函数......这是我发现的唯一有效的东西......请注意创建一个{{1}您正在迭代的数组中的值 所有代码都在PHP 5.5.9,BTW

上进行了测试

我能提出的最好的解决方案(看作兼容性是个问题)就是让两个参数都是可选的:

null

这样,现有代码不会制动,而不是构造一个空的生成器,传递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); 也可以正常工作。