В perl есть выражение local. Оно подменяет указанное значение undef-ом до конца блока. В качестве значения могут выступать глобальные хеши, массивы и скаляры, а так же элементы или срезы хешей и скаляров.
Проблема в том, что хеши пакетов local не сохраняет.
Под хешами пакетов я понимаю хеш с двоеточием на конце (%Пакет::) в котором хранятся символы пакета (GLOB).
package A { sub fn {} $x = 10; @x = qw(1 2); } use DDP; p %A:: # -> { # fn *A::fn (layers: ), # x *A::x (layers: ) # }
Тут @x и $x находятся в одном глобе — *A::x.
Доступ к ним можно получить так:
package A { sub fn {} $x = 10; @x = qw(1 2); } $\ = "\n"; $, = ", "; print $A::x, ${ *A::x{SCALAR} }, ${ *{ $A::{x} }{SCALAR} }; # -> 10, 10, 10 print @A::x, @{ *A::x{ARRAY} }, @{ *{ $A::{x} }{ARRAY} }; # -> 1, 2, 1, 2, 1, 2
То есть вначале получаем GLOB из хеша пакета ($A::{x}), разыменовываем его (*{ $A::{x} }), получаем ссылку на скаляр (*{ $A::{x} }{SCALAR}) и, наконец, разыменовываем скаляр (${ *{ $A::{x} }{SCALAR} }).
GLOB же это такой специальный хеш с предустановленными ключами: SCALAR, ARRAY, HASH, CODE, REF, GLOB, LVALUE, FORMAT, IO, VSTRING.
Каждый из них соответствует отдельному типу значения который может хранится в символе (fn и x — символы в пакете A).
Но вернёмся к local.
use DDP; our %x = qw/a b d c/; { local %x; $x{a} = "R"; p %x; # -> { # a "R" # } } p %x; # -> { # a "b" # d "c" # }
Как видим local подменила our %x до конца блока.
С my %x local отказывается работать (выбрасывает исключение):
@@файл x.pl: my %x = qw/a b/; { local %x; p %x; } @@консоль: $ perl x.pl Can't localize lexical variable %x at x.pl line 13.
А теперь самое интересное: на хеш пакета local не ругается, но и не сохраняет его:
package A { sub fn { 10 } $x = 20; } { local %A::; *A::fn = sub {6}; $A::x = 3; print &A::fn; # -> 6 print $A::x; # -> 3 } print &A::fn; # -> 6 print $A::x; # -> 3
То есть $A::x и A::fn не вернулись к первоначальному состоянию.
Тем не менее если сохранять не хеш %A::, а срез всех его ключей (@A::{keys %A::}), то local сработает:
package A { sub fn { 10 } $x = 20; } { local @A::{keys %A::}; *A::fn = sub {6}; $A::x = 3; print &A::fn; # -> 6 print $A::x; # -> 3 } print &A::fn; # 10 print $A::x; # 20
Вот и ещё одна тайна perl-а раскрыта!
Хотя не до конца. Если у кого-то есть объяснение такому странному поведению local c хешем пакета, то хотелось бы его увидеть в комментариях.
Ну и напоследок предлагаю полюбоваться содержимым пакета main:

Обратите внимание на наш пакет A, который на самом деле main::A.

Все остальные пакеты находятся в пакете main, а пакеты с четвероточиями укладываются в них иерархически образуя древовидную структуру:
package A { sub fn { 10 } $x = 20; } package A::A { $x = 30; } # -> # %main:: # A:: *main::A # fn *A::fn # x *A::x # A:: *A::A:: # x *A::A::x print \%main::A == \%A? "одно и то же": "разное"; # -> одно и то же print $main::{A::}{A::} == $A::A::? "одно и то же": "разное"; # -> одно и то же
Вот и всё. Остаётся только пожелать нам всем отличного программирования!
ссылка на оригинал статьи https://habr.com/ru/articles/585038/
Добавить комментарий