Магия связи не переносится через присвоение, потому что она применяется к самой переменной, а не к значению, которое она содержит.У вас есть несколько вариантов:
Возвращение ссылки:
sub new {tie my $ret, ...; \$ret}
my $counter = Counter->new;
say $$counter;
Назначение глобу:
our ($counter);
*counter = Counter->new; # same new as above
say $counter;
Или вы можете передать переменную в конструктор:
sub new {my $class = shift; tie $_[0], $class}
Counter->new(my $counter);
say $counter;
Вы даже можете создать конструктор, который работает с обоими методами:
sub new {
my $class = shift;
tie $_[0] => $class;
\$_[0]
}
our $glob; *glob = Counter->new;
Counter->new(my $lexical);
В последних двух примерах tie
передается $_[0]
напрямую.Причина этого в том, что элементы @_
являются псевдонимами в списке аргументов, поэтому он работает так, как если бы вы набрали my $counter
в строке tie
.
И, наконец, хотя ваш пример очень ясен и следует передовым методам, в духе TIMTOWTDI вы можете написать весь свой класс следующим образом:
{package Counter;
sub TIESCALAR {bless [0]}
sub FETCH {$_[0][0]++}
sub STORE {$_[0][0] = $_[1]}
sub new {tie $_[1] => $_[0]; \$_[1]}
}
И последнее, что нужно упомянуть.Хотя ваш вопрос касается связанных переменных, вы также можете использовать перегрузку для достижения этого:
{package Counter;
use overload fallback => 1, '""' => sub {$_[0][0]++};
sub new {bless [0]}
}
my $counter = Counter->new; # overloading survives the assignment
say $counter;
Но вы теряете возможность сбрасывать счетчик с помощью присваивания.Вы можете добавить sub set {$_[0][0] = $_[1]}
метод к Counter
.