Perl: while ($ key = each% hash) не останавливается на ключе = 0
Мне это не нужно, очевидно; Мне просто интересно, что здесь происходит. Я скучаю
что-то простое? Могу ли я полагаться на это поведение во всех версиях Perl?)
Perl v5.8.8:
%h = ( 0=>'zero', 1=>'one', 2=>'two' );
while ($k = each %h) {
$v = delete $h{$k};
print "deleted $v; remaining: @h{0..2}\n";
}
выходы
deleted one; remaining: zero two
deleted zero; remaining: two
deleted two; remaining:
man perlfunc
(каждый) не объясняет, почему
while цикл продолжается, когда $k
назначается 0.
Код ведет себя так, как если бы условие в цикле while
были ($k = each %h, defined $k)
.
Если условие цикла фактически изменено на
($k = each %h, $k)
, то это действительно
остановитесь на $k = 0
, как ожидалось.
Он также останавливается на $k = 0
для следующих
повторная реализация each
:
%h = ( 0=>'zero', 1=>'one', 2=>'two' );
sub each2 {
return each %{$_[0]};
}
while ($k = each2 \%h) {
$v = delete $h{$k};
print "deleted $v; remaining: @h{0..2}\n";
}
выводит только:
deleted one; remaining: zero two
Ответы
Ответ 1
Вы вызываете each
в скалярном контексте, поэтому он не работает из-за возвращаемого значения списка.
Как и
while ($line = <FILE>)
имеет специальную обложку для добавления неявного defined
, поэтому
while ($key = each %hash)
В 5.8.8 это происходит в op.c, строки 3760-3766:
case OP_SASSIGN:
if (k1->op_type == OP_READDIR
|| k1->op_type == OP_GLOB
|| (k1->op_type == OP_NULL && k1->op_targ == OP_GLOB)
|| k1->op_type == OP_EACH)
expr = newUNOP(OP_DEFINED, 0, expr);
break;
Я не уверен, что это относится ко всем версиям Perl 5.
См. также: Когда делает() проверку для определения vs правды на PerlMonks. Я не могу найти, где это упоминается в документах Perl (упоминается случай <FILE>
, но я не вижу случая each
).
Ответ 2
cjm является правильным. Я просто хочу добавить, что, когда вы сталкиваетесь со странными вещами, как это часто помогает запустить ваш код через B::Deparse, чтобы увидеть, как Perl понял ваш код. Мне нравится использовать -p-переключатель, чтобы отображать ошибки приоритета.
$ perl -MO=Deparse,p your_example.plx
(%h) = (0, 'zero', 1, 'one', 2, 'two');
while (defined($k = each %h)) {
$v = delete $h{$k};
print "deleted $v; remaining: @h{0..2}\n";
}
your_example.plx syntax OK
Ответ 3
Спасибо, cjm.
Было ясно, какое неявное добавление defined
происходило так же, как глобус, но не там, где это было
документированы. Теперь, по крайней мере, я знаю ограниченные случаи, когда
что применяется специальная обработка.
Но информация должна быть в документации perlfunc,
не только исходный код Perl!