2016-06-14 86 views
4

通常我不會對語言結構感到困惑,但我無法對這裏發生的事情做出正面或反面的評論。發生器::發送工作如何?

<?php 

function action() { 
    for($i=0; $i<10; ++$i) { 
     $ans = (yield expensive($i)); 
     echo "action $ans\n"; 
    } 
} 

function expensive($i) { 
    return $i*2; 
} 

$gen = action(); 
foreach($gen as $x) { 
    echo "loop $x\n"; 
    $gen->send($x); 
} 

打印:

loop 0 
action 0 
action 
loop 4 
action 4 
action 
loop 8 
action 8 
action 
loop 12 
action 12 
action 
loop 16 
action 16 
action 

所以我的循環的每2迭代被跳過,我得到NULL$ans週期性。什麼??

我想$ans會收到$gen->send的結果,如果我沒有在未來yield之前發送任何東西,然後$ans將是空的,但我總是送些什麼東西在每次迭代,那麼什麼是怎麼回事?

+0

嘗試顛倒順序。我認爲(不知道),你需要發送它之前,它可以用在生成器中的回聲。 – apokryfos

+0

@apokryfos顛倒現在的順序?在定義之前,我無法打印'$ ans'。也許'foreach'正在搞亂它...... – mpen

+0

我在說'$ gen-> send($ x); echo「loop $ x \ n」;'並比較差異而不是當前的echo - > send'組合 – apokryfos

回答

1

我認爲'foreach'正在搞砸事情。當foreach循環開始時,會創建一個迭代器,並且我認爲它無法處理我將新事物注入生成器的事實。

此:

<?php 

/** 
* @return Generator 
*/ 
function action() { 
    for($i=0; $i<10; ++$i) { 
     $ans = (yield expensive($i)); 
     echo "action $ans\n"; 
    } 
} 

function expensive($i) { 
    return $i*2; 
} 

$gen = action(); 
while($gen->valid()) { 
    $x = $gen->current(); 
    echo "loop $x\n"; 
    $gen->send($x); 
} 

打印我所期望的:

loop 0 
action 0 
loop 2 
action 2 
loop 4 
action 4 
loop 6 
action 6 
loop 8 
action 8 
loop 10 
action 10 
loop 12 
action 12 
loop 14 
action 14 
loop 16 
action 16 
loop 18 
action 18 

事情變得怪異再次但如果你不是每一次循環send更多:

<?php 

/** 
* @return Generator 
*/ 
function action() { 
    for($i=0; $i<10; ++$i) { 
     $ans = (yield expensive($i)); 
     echo "action $ans\n"; 
    } 
} 

function expensive($i) { 
    echo "expensive $i\n"; 
    return $i; 
} 

$gen = action(); 
while($gen->valid()) { 
    $x = $gen->current(); 
    echo "loop $x\n"; 
    $gen->send($x); 
    $gen->send($x); 
} 

打印:

expensive 0 
loop 0 
action 0 
expensive 1 
action 0 
expensive 2 
loop 2 
action 2 
expensive 3 
action 2 
expensive 4 
loop 4 
action 4 
expensive 5 
action 4 
expensive 6 
loop 6 
action 6 
expensive 7 
action 6 
expensive 8 
loop 8 
action 8 
expensive 9 
action 8 

我覺得這裏發生的事情是send導致action迭代兩次迭代每個while迭代。如果我們刪除兩個sends(),那麼我們會陷入無限循環。所以... send()正在推進迭代器,而current()沒有。我想這也解釋了foreach循環會發生什麼 - foreachsend()都推進了迭代器,這就是爲什麼每個其他結果都被跳過的原因!