Путаница в синтаксисе оператора dimond в парсинге perl и голых словах

Я очень новичок в Perl, поэтому уверен, что моя путаница здесь просто из-за непонимания синтаксиса Perl и того, как он обрабатывает голые слова. Однако я не могу найти хороших ответов на свой вопрос в Интернете.

У меня был код, который я занимаюсь рефакторингом, он выглядел так

@month_dirs = <$log_directory/*>;

Я изменил $ log_directory, чтобы он загружался с файлом конфигурации (точнее, AppConfig). Теперь вместо экспорта $ log_directory мы выводим $ conf, который является объектом AppConfig. Чтобы получить доступ к загруженным переменным, вы обычно вызываете метод для имени переменной, поэтому я попробовал ...

@month_dirs = <$conf->log_directory()."/*">

Это не удается, потому что я не могу вызвать метод $ conf-> log_directory в том месте, где ожидается заглавное слово. Просто поиграю, я попробовал это вместо этого

 $month_directory_command = $conf->log_directory()."/*";
 @month_dirs = <$month_directory_command>;

Это все равно не удается, тихо, без каких-либо указаний на то, что это проблема. Я попытался использовать строку непосредственно в алмазе, но это не удалось, по-видимому, алмазом принимаются только голые слова, а не строки. Я удивлен тем, что, поскольку мне вообще не разрешено использовать строку, я думал, что в большинстве мест Barewords может Вместо этого можно использовать строку, просто потому, что большая часть кода реализует отдельную логику, чтобы принимать голые слова и строки, но это не требуется для реализации таким образом?

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

 $month_directory_command = $conf->log_directory();
 @month_dirs = <$month_directory_command/*>;

Однако мне это кажется некрасивым. Я также не понимаю, почему я могу это сделать, но я не могу создать одно слово с помощью:

 $bare_word = $conf->log_directory()/*

or

 $month_directory_command = $conf->log_directory();
 $bare_word = $month_directory_command/*;
 @month_dirs = <$bare_word>;     

Почему одни переменные работают с голыми словами, а другие нет? почему я могу использовать переменную масштабирования, но не если она возвращается из вызова метода?

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

Я надеюсь, что кто-то может помочь мне лучше понять синтаксис голого слова здесь. Что определяет, когда я могу использовать переменную как часть простого слова и могу ли я сохранить ее как переменную?

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

Кстати, кажется, предложение в любом случае не использовать голые слова в perl? Есть ли какой-то способ избежать голых слов в операторе алмаза?


person dsollen    schedule 22.12.2015    source источник
comment
включите use strict; и use warnings;. Голое слово - это слово, вокруг которого ничего нет. Оператор «ромб» означает, что это больше не просто слово.   -  person Sobrique    schedule 22.12.2015
comment
См. Раздел об операторах ввода-вывода в perlop   -  person Håkon Hægland    schedule 22.12.2015
comment
У вас есть странное представление о том, что такое голое слово. Термин относится к строке без кавычек, содержащей только буквенно-цифровые символы или подчеркивание, что не означает ничего другого в грамматике Perl. Таким образом, по определению, $bare_word не и не $log_directory/*   -  person Borodin    schedule 22.12.2015


Ответы (3)


Вы ошибаетесь, что алмазный оператор <> работает только с голыми словами:

$ perl -E'say for <"/*">'
/bin
/boot
/dev
...

(Фактически, голое слово - это просто идентификатор, который не имеет сигилы и запрещен use strict 'subs';, поэтому ни один из ваших примеров не подходит.)


Этот:

@month_dirs = <$log_directory/*>;

работает, потому что уровень интерполяции двойных кавычек выполняется внутри <>, а скалярные переменные, такие как $log_directory, интерполируются.

Это эквивалентно:

@month_dirs = glob("$log_directory/*");

Этот:

@month_dirs = <$conf->log_directory()."/*">

терпит неудачу, потому что > в $conf->log_directory() преждевременно закрывает ромбовидный оператор, запутывая синтаксический анализатор.

Он разбирается как:

<$conf->

(вызов glob), за которым следует

log_directory()."/*">

что является синтаксической ошибкой.


Этот:

$month_directory_command = $conf->log_directory()."/*";
@month_dirs = <$month_directory_command>;

терпит неудачу, потому что

<$month_directory_command>

эквивалентно

readline($month_directory_command)

а не

glob("$month_directory_command")

Из perldoc perlop:

Если в угловых скобках содержится простая скалярная переменная (например, $foo), то эта переменная содержит имя дескриптора файла, из которого следует вводить данные, или его typeglob, или ссылку на него.

[...]

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

Итак, вы пытаетесь читать из дескриптора файла ($month_directory_command), который еще не был открыт.

Включение предупреждений с помощью use warnings 'all'; предупредило бы вас об этом:

readline() on unopened filehandle at foo line 6.

Этот:

$bare_word = $conf->log_directory()/*;

терпит неудачу, потому что вы пытаетесь объединить результат вызова метода со строкой, не заключенной в кавычки; чтобы объединить строки, вы должны интерполировать их в строку с двойными кавычками или использовать оператор конкатенации.

Вы могли сделать:

$bare_word = $conf->log_directory() . "/*";
@month_dirs = <"$bare_word">;

(хотя $bare_word вовсе не голое слово, это скалярная переменная.)

Обратите внимание, что:

@month_dirs = <$bare_word>;

(без кавычек) будет интерпретироваться как readline, а не glob, как объяснено в perlop выше.

В целом, однако, использование оператора glob напрямую, вероятно, будет менее запутанным:

@month_dirs = glob( $conf->log_directory() . "/*" );
person ThisSuitIsBlackNot    schedule 22.12.2015

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

$data = <$fh>;

Это действует как функция чтения; полное (не символьное) имя этой функции - readline. Эта строка источника эквивалентна

$data = readline( $fh );

Однако ваша исходная форма была

@month_dirs = <$log_directory/*>;

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

@month_dirs = glob( "$log_directory/*" );

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

@month_dirs = glob( $conf->log_directory()."/*" );
person LeoNerd    schedule 22.12.2015

голое слово может быть только внутри скобок ‹>, синтаксис внутри - это синтаксис оболочки, более perl

# wrong -     
$bare_word = $month_directory_command/*;
# right - star is allowed because it is inside the quote single or double
$bare_word = "$month_directory_command/*";

# star is allowed simply because it is inside the bracket
@month_dirs = <$month_directory_command/*>;
person Gang    schedule 22.12.2015