Какая из них хорошая практика, лексический дескриптор файла или 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, $!));
...