2010-07-29 2 views
3

Итак, я считаю, что это имеет какое-то отношение к разнице между массивами и списками, но я не знаю, что здесь происходит. Может ли кто-нибудь объяснить, как и почему Perl обрабатывает выражение типа (1..4) иначе, чем (1, 2, 3, 4) и @{[1..4]}?Вызов «скаляра» по результатам оператора диапазона (..) в Perl

$ perl -de1 

Loading DB routines from perl5db.pl version 1.31 
Editor support available. 

Enter h or `h h' for help, or `man perldebug' for more help. 

main::(-e:1): 1 
    DB<1> x scalar (1,2,3,4) 
0 4 
    DB<2> x scalar (1..2,3,4) 
0 4 
    DB<3> x scalar (1,2..3,4) 
0 4 
    DB<4> x scalar (1,2,3..4) 
0 '' 
    DB<5> sub foo { (1..4) } # (the actual problem case, except 4 would be a variable) 
    DB<6> x scalar foo() 
0 '' 
    DB<7> sub bar { @{[1..4]} } # (the workaround) 
    DB<8> x scalar bar() 
0 4 
+2

Для дальнейшего просвещения попробуйте 'print scalar (5,6,7,8)' и 'print scalar (@ a = (5,6,7,8))' и, возможно, даже 'print scalar (() = (5,6,7,8)) ' – mob

+0

Да, я добрался до этого. '<3' – fennec

ответ

11

Под «диапазоном оператора», которая выдает список только не существует в скалярном контексте - .. оператор при использовании в скалярном контексте является «флип-флоп оператор» вместо этого. Флип-флоп-оператор начинает возвращать false, продолжает возвращать false до тех пор, пока его левый аргумент не станет истинным, а затем продолжит возвращать значение true, пока его правый аргумент не станет истинным, после чего он вернет значение false и вернется в исходное состояние. Если все это звучит довольно бесполезно, считают

while (<>) { 
    print if /BEGIN/ .. /END/; 
} 

Оператор .. начинает ложно, поэтому строки из файла не выводятся на печать. Но как только регулярное выражение /BEGIN/ соответствует, триггер становится истинным, и все следующие строки будут напечатаны до тех пор, пока не будет найдено регулярное выражение /END/. Из строки, следующей за «END», триггер снова будет ошибочным. Таким образом, эффект заключается только в печати строк между (и включая, но вы можете контролировать это) «BEGIN» и «END».

Есть немного больше магии с $., если обе стороны постоянные, но это не очень важно. Подробнее о флип-флопе в разделе perldoc perlop.

+0

Этот оператор наверняка популярен сегодня! – Ether

+0

Whee! Я предполагаю, что я ожидал, что выражение будет оцениваться в контексте списка, а затем скалярное. «perldoc -f scalar» намекает на это, я полагаю, но в лучшем случае двусмысленен: * Нет эквивалентного оператора, чтобы заставить выражение быть интерполированным в контексте списка, потому что на практике это никогда не требуется. Однако, если вы действительно хотели это сделать, вы могли бы использовать конструкцию '@ {[(некоторое выражение)]}', но обычно достаточно простое (некоторое выражение) '. – fennec

+1

@fennec да, то, что вы изначально ожидали просто не происходит. Список и скалярный контекст различны, и ничто не «оценивается в контексте списка, а затем скалярное», если только вы специально не заставляете это произойти. Многие операторы будут вести себя так, как если бы это было так (с эквивалентными побочными эффектами в любом контексте, и либо возвращать список в контексте списка, либо счет в скалярном контексте, либо возвращать одно значение в любом контексте), но некоторые удивятся вы, делая что-то значительно отличающееся в одном контексте, чем другое. 'm // g' и' split' - другие, которые нужно искать. – hobbs

Смежные вопросы