Мы объясним это подробно в Промежуточный Perl .
Общий синтаксис для поиска переменных:
SIGIL BLOCK INDEXY-THING
Для простого скаляра, который выглядит следующим образом:
print $ { foo };
Вы, вероятно, видели это, когда вам нужно отделить имя переменной от окружающих ее вещей:
print "abc${foo}def\n";
Если у вас просто есть идентификатор Perl в блоке и нет окружающего беспорядка, вы можете оставить скобки, что является распространенным случаем:
print $foo;
Однако для разыменования ссылки это тоже самое:
SIGIL BLOCK-RETURNING-REFERENCE INDEXY-THINGS
Если вещь, которую вы получаете в блоке, является ссылкой, Perl пытается разыменовать ее так, как вы ее просили:
my $ref = \ '12345';
print $ { $ref };
Это настоящий блок, а не просто сахар. Вы можете иметь столько утверждений, сколько захотите:
print $ { my $ref = \ '1234'; $ref };
Теперь вы не просто указываете идентификатор Perl, поэтому Perl не предполагает, что вы даете ему идентификатор, и он выполняет код и использует результат в качестве ссылки. Рассмотрим разницу между этими почти идентичными say
утверждениями:
use 5.010;
our $foo = "I'm the scalar";
sub foo { \ "I'm the sub" }
say ${foo};
say ${foo;};
В эту секунду say
Perl видит точку с запятой, понимает, что это не идентификатор, интерпретирует код внутри фигурных скобок как текст и возвращает результат. Поскольку результат является ссылкой, он использует ${...}
для разыменования его. Неважно, где вы это делаете, так что вы делаете это внутри строки в двойных кавычках не является особенным.
Также обратите внимание на our
там. Это важно сейчас, когда вы собираетесь рассмотреть что-то более сложное:
use 5.010;
our $foo = "I'm the scalar";
sub foo { \ "I'm the sub" }
sub baz { 'foo' }
say ${foo};
say ${foo;};
say ${baz;};
Perl интерпретирует этот последний say
как код и видит результат не как ссылку; это простая строка foo
. Perl видит, что это не ссылка, но теперь она находится в контексте разыменования, поэтому она делает символическую ссылку (как Грег Бэкон описывает ). Поскольку символьные ссылки работают с переменными в таблице символов, то $foo
должна была быть переменной пакета.
Так как это легко испортить, у strict
есть удобная проверка. Однако, когда вы выключаете его, не удивляйтесь, когда он вас кусает. :)