Как результат "0" от readdir () не ложен в состоянии while? - PullRequest
6 голосов
/ 09 мая 2009

См. Также: Где в документации сказано, что во время тестирования readdir на определенность? . ( Не дубликат; просто тесно связаны. )


Многие люди считают цикл ниже идиоматическим:

while (defined(my $file = readdir($dir)) {
    ...
}

вместо:

while (my $file = readdir($dir)) {
    ...
}

потому что предположительно с последней версией, если имя файла просто «0» (ноль), он должен завершить цикл, тогда как он возвращает «undef», когда больше нет файлов.

Однако в какой-то момент в прошлом этот тест для defined() перестал быть необходимым - кажется, существует специальный код, который позволяет последней версии работать независимо.

Я хотел бы знать, как это работает?

Любопытно, если я заменю вызов на readdir() звонком на foo() вместо:

sub foo
{
    my ($dir) = @_;
    return readdir($dir);
}

while (my $file = foo($dir)) {
    ...
}

тогда код делает , что я и ожидал, и завершает цикл, когда найден файл с именем "0".

(протестировано с Perl 5.8.9 на MacOS X 10.5.6)

1 Ответ

12 голосов
/ 09 мая 2009

Это волшебство. В частности, во время магии (задокументировано в perlsyn, perlop и, возможно, в других местах, которые я не помню). Perl позволяет вам определенные сокращенные обозначения. Если вы хотите увидеть, что Perl делает за вашей спиной, вы можете использовать B::Deparse. Вот файл, который использует сокращенный цикл:

#!/usr/bin/perl

use strict;
use warnings;

opendir my $dir, "/tmp" or die "$!";

while (my $file = readdir($dir)) {
    print "$file\n";
}

Если вы запустите perl -MO=Deparse filename.pl, вы получите код, который видит Perl:

use warnings;
use strict 'refs';
die "$!" unless opendir my $dir, '/tmp';
while (defined(my $file = readdir $dir)) {
    do {
        print "$file\n"
    };
}
filename.pl syntax OK
...