2013-05-01 5 views
3

у меня есть это:Perl Constant, кажется, не работает

use constant JAR_FILE => qr/\.jar$/; 

my @dir_list = ...; 
my @jar_list; 
find (sub { 
    return unless -f; 
    return unless JAR_FILE; #THIS IS THE TROUBLED LINE 
    push @jar_list, $File::Find::name; 
    }, @dir_list; 

say join ": ", @jar_list; 

Это выводит все файлы в @dir_list - банка файлах и не баночка файлах;

Однако это:

use constant JAR_FILE => qr/\.jar$/; 

my @dir_list = ...; 
my @jar_list; 
find (sub { 
    return unless -f; 
    return unless $_ =~ JAR_FILE; #Now explicitly do the comparison 
    push @jar_list, $File::Find::name; 
    }, @dir_list; 

say join ": ", @jar_list; 

печатает только файлы банку.

И это также выводит только банку файлы:

# use constant JAR_FILE => qr/\.jar$/; 

my @dir_list = ...; 
my @jar_list; 
find (sub { 
    return unless -f; 
    return unless /\.jar$/; #Use regex and not constant regex. 
    push @jar_list, $File::Find::name; 
    }, @dir_list; 

say join ": ", @jar_list; 

Почему первый один return unless JAR_FILE; не работать, пока return unless $_ =~ JARFILE; и return unless /\.jar$/; и работу?

ответ

7

Это не имеет никакого отношения к константам.

>perl -wE"$_ = '.txt'; say qr/\.jar$/ ?1:0;" 
1 

>perl -wE"$_ = '.txt'; say /\.jar$/ ?1:0;" 
0 

>perl -wE"$_ = '.txt'; say $_ =~ qr/\.jar$/ ?1:0;" 
0 

qr// компилирует регулярное выражение и возвращает его, в то время как оператор матча (m// ака //) преформы матча регулярного выражения.

С qr// всегда возвращает что-то истинное (скомпилированное регулярное выражение), return unless qr/\.jar$/; никогда не вернется.

=~ qr/\.jar$/ работает, потому что =~ подразумевает оператор матча, если операнд RHS не является оператором матча (m//), оператор подстановки (s///) или перевести оператор (tr///).

my $re = qr/\.jar$/; 
$_ =~ $re 

коротка для

my $re = qr/\.jar$/; 
$_ =~ /$re/ 

который долго

my $re = qr/\.jar$/; 
/$re/ 

Если опустить оба // и =~, у вас нет оператора матча больше.

+0

Я думаю, главное в том, что '' т /../ неявно предполагает матч против '$ _', если вы не укажете' = ~ 'так же, как '-f' предполагает, что он должен проверить' $ _', если вы не укажете проверяемую переменную. Это один из немногих раз, когда я буду использовать этот тип неявного '$ _'. Обычно я расскажу людям, чтобы они не делали подобные вещи, потому что это сломается, когда вы меньше всего этого ожидаете. Как в этой ситуации. –

+0

Ты все еще думаешь, что все это неправильно. Почему постоянная причина регулярного выражения? Главное, что qr // не вызывает никакого совпадения вообще. Добавил немного моего ответа, чтобы подробно остановиться на этом. – ikegami

1

Дело в том, что qr// не соответствует ни одному, пока вы его не скажете.
(Это единственная причина qr// даже часть языка)

my $match_jar = qr/\.jar$/; 

$_ = undef; 

print $match_jar, "\n" if $match_jar; # always prints 

for(qw' matches.jar doesnt.txt '){ 
    print $_, "\n" if $_ =~ $match_jar; # only prints "matches.jar" 

    # here is the reason qr// exists 
    my $bool = /\.jar$/; 
    print $bool, "\n"; # prints 1 or '' 
} 
(?^:\.jar$) 
matches.jar 
1 


Так, как вместо использования constant вы определите «постоянный» себя.
(Примечание. constant на самом деле просто создает inlinable subroutines, Perl на самом деле не имеют константы)

sub MATCH_JAR_FILE(_){ $_[0] =~ /\.jar$/ } # 5.10.0 or later 

... 
    # test against $_ 
    return unless MATCH_JAR_FILE; 
... 
    return unless MATCH_JAR_FILE($var); 
... 

Перед 5.10 вам придется писать по-другому.

sub MATCH_JAR_FILE(;$){ 
    @_ = $_ unless @_; # doesn't get lexical $_ 
    $_[0] =~ /\.jar$/ 
} 

Обратите внимание, что вам придется заменить любое вхождение ... =~ JAR_FILE; с MATCH_JAR_FILE(...)


Если вы не возражаете, используя модули из CPAN вы можете использовать Want. Тогда у вас будет другой способ использования подпрограммы.

use Want 'want'; 

sub JAR_FILE(_){ 
    return $_[0] =~ /\.jar$/ if want 'BOOL'; 
    return qr/\.jar$/ 
} 

... 
    # test against $_ 
    return unless JAR_FILE; # bool 
... 
    return unless $var =~ JAR_FILE; 
... 
    return unless JAR_FILE($var); # bool 
... 

Перед 5.10 вы бы, вероятно, написать его совсем по-другому.

use Want 'want'; 

sub JAR_FILE(){ 
    return /\.jar$/ if want 'BOOL'; 
    return qr/\.jar$/ 
} 

... 
    # test against $_ 
    return unless JAR_FILE; # bool 
... 
    return unless $var =~ JAR_FILE; 
... 
    # return unless JAR_FILE($var); # doesn't work 
... 
Смежные вопросы