Подтвердить что ты не робот

Почему я не могу использовать алмазный оператор с массивом в Perl?

код

$ 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";

Run

$ perl 1.pl
1
5
$

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

В основном правила:

<bareword> ~~  readline bareword
<$scalar>  ~~  readline $scalar
<$array[0]> ~~ glob "$array[0]"
<anything else> ~~ glob ...

Ответ 4

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

Вместо этого используйте readline:

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