Что происходит внутри, когда у вас есть ‹FH›, ‹› или ‹*› в perl?

Прошу прощения, если этот вопрос звучит просто, я намерен подробно понять, как работают эти (эти?) Конкретные операторы, и мне не удалось найти удовлетворительное описание в perldocs (возможно, он существует где-то я просто не мог найти его на всю жизнь)

В частности, мне интересно узнать,

a) <>

б) <*> или любой другой шар и

c) <FH>

принципиально похожи или различны, и как они используются внутри компании.

Я создал свои собственные функции тестирования, чтобы понять это (представлено ниже). У меня до сих пор нет полного понимания (мое понимание может даже быть неправильным), но вот что я пришел к выводу:

  • <>
    • In Scalar Context: Reads the next line of the "current file" being read (provided in @ARGV). Questions: This seems like a very particular scenario, and I wonder why it is the way it is and whether it can be generalized or not. Also what is the "current file" that is being read? Is it in a file handle? What is the counter?
    • В контексте списка: считывает ВСЕ файлы в @ARGV в массив
  • <list of globs>
    • In Scalar Context: Name of the first file found in current folder that matches the glob. Questions: Why the current folder? How do I change this? Is the only way to change this doing something like < /home/* > ?
    • В контексте списка: все файлы, соответствующие глобу в текущей папке.
  • <FH>, кажется, просто возвращает undef при присвоении переменной. Вопросы: почему это undef? Разве у него нет типа? Это ведет себя аналогичным образом, когда FH не является файловым дескриптором с открытым кодом?

Общий вопрос: что обрабатывает значение ‹> и других во время выполнения? В скалярном контексте возвращается ли какая-либо ссылка или переменные, которым мы их назначаем, идентичны любому другому скаляру без ссылки?

Я также заметил, что, хотя я назначаю их последовательно, вывод каждый раз сбрасывается. то есть я бы предположил, что когда я это сделаю

$thing_s = <>;
@thing_l = <>;

@thing_l будет отсутствовать первый элемент, поскольку он уже был получен $thing_s. Почему это не так?

Код, использованный для тестирования:

use strict;
use warnings;
use Switch;
use Data::Dumper;

die "Call with a list of files\n" if (@ARGV<1);
my @whats = ('<>','<* .*>','<FH>');
my $thing_s;
my @thing_l;
for my $what(@whats){
    switch($what){
                    case('<>'){
                        $thing_s = <>;
                        @thing_l = <>;
                    }
                    case('<* .*>'){
                            $thing_s = <* .*>;
                            @thing_l = <* .*>;
                    }
                    case('<FH>'){
                            open FH, '<', $ARGV[0];
                            $thing_s = <FH>;
                            @thing_l = <FH>;
                    }

    }
    print "$what in scalar context is: \n".Dumper($thing_s)."\n";
    print "$what in list context is: \n".Dumper(@thing_l)."\n";
}

person heypano    schedule 17.09.2013    source источник
comment
Раздел «Операторы ввода-вывода» в perldoc perlop должен дать вам хорошее начало.   -  person ThisSuitIsBlackNot    schedule 18.09.2013
comment
@thing_l действительно теряет первый элемент в этом случае. Посмотри снова.   -  person Borodin    schedule 18.09.2013
comment
Спасибо! Бородин, вообще-то ты прав! Я ДЕЙСТВИТЕЛЬНО хотел сказать, что происходит с ‹*. *›. Я думаю, ЭТО сбрасывается.   -  person heypano    schedule 18.09.2013


Ответы (2)


<> штуки - все итераторы. Все эти варианты имеют общее поведение:

  • При использовании в контексте списка возвращаются все оставшиеся элементы.
  • При использовании в скалярном контексте возвращается только следующий элемент.
  • Используемый в скалярном контексте, он возвращает undef, когда итератор исчерпан.

Эти последние два свойства делают его пригодным для использования в качестве условия в while циклах.

Есть два типа итераторов, которые можно использовать с <>:

  • Файловые дескрипторы. В этом случае <$fh> эквивалентно readline $fh.
  • Globs, поэтому <* .*> эквивалентно glob '* .*'.

<> анализируется как строка чтения, когда он не содержит ничего, голое слово или простой скаляр. Можно вставить более сложное выражение, например <{ ... }>.

Во всех остальных случаях он анализируется как глобус. Это можно сделать явным, используя кавычки: <"* .*">, но вы действительно должны быть явными и вместо этого использовать функцию glob.

Некоторые детали отличаются, например где сохраняется состояние итератора:

  • При чтении из дескриптора файла дескриптор файла сохраняет это состояние итератора.
  • При использовании формы глобуса каждое выражение глобуса имеет собственное состояние.

Другая часть - если итератор может перезапуститься:

  • glob перезапускается после возврата единицы undef.
  • дескрипторы файлов могут быть перезапущены только путем поиска - не все FH поддерживают эту операцию.

Если в <> не используется дескриптор файла, то по умолчанию используется специальный дескриптор файла ARGV. <ARGV> ведет себя следующим образом:

  • Если @ARGV пусто, то ARGV равно STDIN.
  • В противном случае элементы @ARGV рассматриваются как имена файлов. Выполняется следующий псевдокод:

    $ARGV = shift @ARGV;
    open ARGV, $ARGV or die ...; # careful! no open mode is used
    

    Скаляр $ARGV содержит имя файла, а дескриптор файла ARGV - этот дескриптор файла.

  • Когда ARGV будет eof, открывается следующий файл из @ARGV.
  • Только когда @ARGV полностью пуст, <> может вернуть undef.

На самом деле это можно использовать как трюк для чтения из многих файлов:

local @ARGV = qw(foo.txt bar.txt baz.txt);
while (<>) {
  ...;
}
person amon    schedule 17.09.2013
comment
Идеально. Большое спасибо. - person heypano; 18.09.2013
comment
Nit: Re Нулевой дескриптор файла особенный. Поведение <> выглядит следующим образом. Это совсем не особенное. <> - это просто сокращение от <ARGV>, которое является сокращением от readline(ARGV). Остальное - собственность ARGV. - person ikegami; 18.09.2013
comment
Nit: <* .*> больше похож на glob q<* .*>, чем на glob '* .*'. - person ikegami; 18.09.2013
comment
@ikegami Спасибо за комментарии. Но я не понимаю второй: нет никакой разницы между двумя кавычками, за исключением того, какие символы должны быть экранированы, поскольку они будут разделителями. Вы имели в виду это (минутка маленькая придурка), или я что-то пропустил? - person amon; 18.09.2013
comment
Другое дело, если выражение содержит ', < или >. - person ikegami; 18.09.2013

Что обрабатывает значение <> и других во время выполнения?

Компилятор Perl очень хорошо осведомлен о контексте и часто должен выбирать между несколькими неоднозначными интерпретациями сегмента кода. Он будет компилировать <> как вызов readline или glob в зависимости от того, что находится внутри скобок.

В скалярном контексте возвращается ли какая-либо ссылка или переменные, которым мы их назначаем, идентичны любому другому скаляру без ссылки?

Я не уверен, о чем вы здесь спрашиваете или почему вы думаете, что переменные, которые принимают результат <>, должны отличаться от других переменных. Это всегда простые строковые значения: либо имя файла, возвращаемое glob, либо некоторые данные файла, возвращаемые readline.

<FH> просто возвращает undef при присвоении переменной. Вопросы: Почему это undef? Разве у него нет типа? Это ведет себя аналогичным образом, когда FH не является файловым дескриптором с голыми словами?

Эта форма будет рассматривать FH как дескриптор файла и возвращать следующую строку данных из файла, если он открыт, а не в eof. В противном случае возвращается undef, чтобы указать, что ничего действительного не может быть прочитано. Perl очень гибок с типами, но undef ведет себя как собственный тип, как nil в Ruby. Оператор ведет себя одинаково, независимо от того, является ли FH глобальным дескриптором файла или (переменной, содержащей) ссылкой на typeglob.

person Borodin    schedule 17.09.2013