Какая из них хорошая практика, лексический дескриптор файла или typeglob?

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

open $fh, $filename;

Но большинство книг Perl, включая The Llama Book, используйте typeglob, например:

open LOGFILE, $filename;

Так в чем же разница? Какой из них считается лучшей практикой?

Ответы

Ответ 1

Лексические дескрипторы файлов могут быть легко переданы в качестве аргументов, дескрипторы файлов не могут. Typeglobs могут (или, по крайней мере, ссылаться на них, могут), но что-то беспорядочное. Подумайте о том, чтобы придерживаться лексических переменных и не забудьте сначала объявить их, поэтому вы знаете, что они действительно лексические, а не локальные или глобальные. То есть.

my $fh;
open $fh, $filename;

Также рассмотрите возможность использования IO::Handle или IO::File в качестве параметров. Раньше был FileHandle, но был проинформирован ysth ниже, что FileHandle теперь просто использует "IO:: Handle" по очереди, что для меня новость 5.6, но здесь есть чему поучиться.: -)

Кроме того, не забудьте use strict: -)

Ответ 2

Самое раннее издание Llama Book - с 1993 года, прежде чем лексические дескрипторы файлов были частью языка Perl. Лексические дескрипторы файлов являются лучшей практикой по целому ряду причин. Наиболее важными недостатками typeglobs являются

  • они всегда являются глобальными по объему, что может привести к коварным ошибкам, подобным этому:

    sub doSomething {
      my ($input) = @_;
      # let compare $input to something we read from another file
      open(F, "<", $anotherFile);
      @F = <F>; 
      close F;
      do_some_comparison($input, @F);
    }
    
    open(F, "<", $myfile);
    while (<F>) {
        doSomething($_);   # do'h -- just closed the F filehandle
    }
    close F;
    
  • им сложнее перейти к подпрограмме, чем лексический дескриптор файла

    package package1;
    sub log_time { # print timestamp to filehandle
        my ($fh) = @_;
        print $fh scalar localtime, "\n";
    }
    
    package package2;
    open GLOB, '>', 'log1';
    open $lexical, '>', 'log2';
    
    package1::log_time($lexical);         # works as expected
    package1::log_time(GLOB);             # doesn't work
    package1::log_time('GLOB');           # doesn't work
    package1::log_time(*GLOB);            # works
    package1::log_time(package2::GLOB);   # works
    package1::log_time('package2::GLOB'); # works
    

См. также: Почему открытые вызовы с тремя аргументами с автообновленными файловыми дескрипторами являются передовой практикой Perl?

Ответ 3

Когда используются лексические переменные, дескрипторы файлов имеют область этих переменных и автоматически закрываются всякий раз, когда вы покидаете эту область:

{
   open my $fh, '<', 'file' or die $!;
   # ...
   # the fh is closed upon leaving the scope
}

Таким образом, вы не создаете постоянные глобальные переменные.

Ответ 4

Использование дескриптора файла typeglob не рекомендуется, потому что, если вы не обращаете внимания, это может привести к нескольким проблемам. Например: если вы создаете рекурсивную функцию, которая повторно использует один и тот же типglob, вы получите некоторые предупреждения при попытке закрыть дескриптор файла, если вы не создадите временную ограниченную оболочку на основе пакетов. Лексические переменные привязаны к блоку, в котором они определены, а область typeglob - для полного пакета, в котором он определен.

Для возобновления:

Если вы хотите остаться с дескриптором файла typeglob, обязательно создайте временную ограниченную оболочку на основе пакетов:

...
local *FH;
open FH, '<', $filepath or die(sprintf('Could not open %s: %s', $filepath, $!));
...

else, используйте лексическую переменную

...
open my $fh, '<', $filepath or die(sprintf('Could not open %s: %s', $filepath, $!));
...