История вопроса:
В Perl можно ограничивать область действия переменных через операторы my (лексическая видимость) и local (динамическое временное переназначение). local широко применяется для переопределения глобальных переменных и специальных дескрипторов (типа $_, $/, $@, %ENV).
Проблема:
main проблема — путаница между динамическим и лексическим scope. local не создает новую переменную, а временно подменяет значение в глобальной (или package) переменной в пределах выполнения блока. Это особенно критично при переназначении таких переменных, как $/ (разделитель строк), $_ (default variable), $^W (warning flag), %ENV, STDIN/STDOUT.
Решение:
Пример кода:
our $Global = "Hello!"; sub change1 { my $Global = "Bye!"; print "$Global "; } sub change2 { local $Global = "Bye!"; print "$Global "; } print "$Global "; # Hello! change1(); # Bye! print "$Global "; # Hello! change2(); # Bye! print "$Global "; # Hello!
Ключевые особенности:
Может ли local применяться к лексическим переменным, объявленным через my?
Нет, local работает только с package-глобальными переменными. На my-объектах он бессилен.
Что произойдет при применении local к специальным дескрипторам, например, STDIN?
Можно временно переназначить STDIN/STDOUT/stdin через local, например, чтобы подменить входной/выходной поток в подпрограмме без глобального эффекта. После выхода из блока handle будет восстановлен.
В чём критическая разница между local и my при рекурсивном вызове функций?
local обеспечивает "push/pop" стек значений — каждый вызов временно переопределяет значение пакета, а вложенные вызовы получают это переопределенное значение. my предоставляет единственное лексическое значение в рамках блока без наследования внутрь.
В тесте используют local для подмены %ENV, после выхода из блока неожиданные side-effects в других потоках, потому что код многопоточный и local применен не по назначению.
Плюсы:
Минусы:
Подменяют специальные переменные ($/, $@, $SIG) только на время вызова нужного блока, после чего изменения корректно откатываются.
Плюсы:
Минусы: