2016-08-02 8 views
3

Если я хочу найти размер массива, созданный <>, почему это не работает?Размер массива, генерируемого <>?

print "Number of .DOC and .PDF files is: " scalar(<*.PDF *.DOC>); 

Вместо этого указывается имя первого файла соответствия.

+0

@ user2864740 Как превратить список в массив в том же самом выражении? – CJ7

+0

О, я был так не прав: см. Http://perldoc.perl.org/perlfunc.html#glob-EXPR «В * скалярном контексте *, glob выполняет итерацию через такое расширение имени файла ..» – user2864740

ответ

10

Начнем с выяснения некоторых из ваших заблуждений.

  • glob[1] никогда не возвращает массив. Операторы не возвращают массивы [2]; они возвращают скаляры. Иногда нет, иногда один, иногда много.

  • scalar влияет на операторов, а не на значения, которые они возвращают. В частности, scalar заставляет оператор внутри оцениваться в скалярном контексте.

  • Как на оператора влияет контекст, зависит от каждого отдельного оператора. Единственная константа состоит в том, что они должны возвращать ровно один скаляр в скалярном контексте. Существует много variety в том, что они предпочитают возвращать в скалярном контексте.

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


Решение:

  • Памяти эффективного решения:

    my $num_files = 0; 
    ++$num_files while <*.PDF *.DOC>; 
    print "Number of .DOC and .PDF files is: $num_files\n"; 
    
  • Более быстрое решение:

    my @qfns = <*.PDF *.DOC>; 
    print "Number of .DOC and .PDF files is: " . @qfns . "\n"; 
    
  • встраиваемая версия выше:

    print "Number of .DOC and .PDF files is: " . @{[ <*.PDF *.DOC> ]} . "\n"; 
    
  • Еще быстрее, менее расточительным, но более продвинутое решение:

    print "Number of .DOC and .PDF files is: " . (() = <*.PDF *.DOC>) . "\n"; 
    

    list assignment operator в скалярном контексте возвращает количество скаляров, возвращенных его РИТ.

  • Уборщик/очиститель?

    my $num_files =() = <*.PDF *.DOC>; 
    print "Number of .DOC and .PDF files is: $num_files\n"; 
    

  1. <*.PDF *.DOC> это ярлык для glob(qq<*.PDF *.DOC>)

  2. для @a в определенных ситуациях За исключением (в том числе \@a, @a = LIST и массива манипуляторов, как push @a, LIST).

+1

Я бы использовал конкатенацию вместо '0 +' для принудительного применения скалярного контекста - например 'print 'Число файлов .DOC и .PDF:. (() = <*.PDF *.DOC>); ' –

+1

@Dave Cross, Это то, что я тоже буду использовать, и так как я не придерживаюсь того, что использовал OP в любом случае, я обновил свой ответ – ikegami