Почему я не могу использовать оператор diamond с массивом в Perl? - PullRequest
11 голосов
/ 29 ноября 2010

Код

$ cat test1
hello 
i am 
lazer

nananana
$ cat 1.pl
use strict;
use warnings;

my @fh;
open $fh[0], '<', 'test1', or die $!;

my @res1 = <$fh[0]>;  # Way1: why does this not work as expected?
print @res1."\n"; 

my $fh2 = $fh[0];
my @res2 = <$fh2>;    # Way2: this works!
print @res2."\n";

Пробег

$ perl 1.pl
1
5
$

Я не являюсьуверен, почему Way1 не работает должным образом, в то время как Way2 работает.Разве эти два метода не одинаковы?Что здесь происходит?

Ответы [ 4 ]

14 голосов
/ 29 ноября 2010

Потому что от perlop :

Если то, что находится в угловых скобках, не является ни файловым дескриптором, ни простой скалярной переменной, содержащей имя файлового дескриптора, ссылку на typeglob или typeglob, то это интерпретируется как шаблон имени файла, который нужно глобализировать, и как список имен файлов или следующего имени файла в списке возвращается, в зависимости от контекста. Это различие определяется только по синтаксическому признаку. Это означает, что <$x> всегда является readline () из косвенного дескриптора, но <$hash{key}> всегда является glob ().

Вы можете записать оператор <> как readline , чтобы избежать проблем с этой магией.

14 голосов
/ 29 ноября 2010

Из-за двойственной природы оператора <> (т. Е. glob или readline ?) Правила таковы, что для работы в режиме readline можно иметь только голое словоили простой скаляр внутри скобок.Поэтому вам придется либо присвоить элемент массива простому скаляру (как в вашем примере), либо напрямую использовать функцию readline.

8 голосов
/ 29 ноября 2010

Что-либо более сложное, чем голое слово (интерпретируемое как дескриптор файла) или простой скаляр $var, интерпретируется как аргумент функции glob().Только голые слова и простые скаляры обрабатываются как файловые дескрипторы, которые должны повторяться оператором <...>.

Основные правила:

<bareword> ~~  readline bareword
<$scalar>  ~~  readline $scalar
<$array[0]> ~~ glob "$array[0]"
<anything else> ~~ glob ...
6 голосов
/ 29 ноября 2010

Это потому, что <$fh[0]> анализируется как glob($fh[0]).

Используйте readline вместо:

my @res1 = readline($fh[0]);
...