Как я могу вызывать методы для связанной переменной?

Я только начал изучать галстук. У меня есть класс с именем Link, который я хотел бы сделать следующим образом:

  • если получено, вернуть адрес ссылки
  • если сохранено, сохраните новый адрес
  • иметь возможность вызывать методы на нем

Пока что мой код:


package Link;

sub FETCH {
    my $this = shift;
    return $this->{"site"};
}

sub STORE {
    my ($self,$site) = @_;
    $self->{"site"}   = $site;
}

sub print_method {
    my $self = shift;
    print $self->{"site"};
}

sub TIESCALAR {
    my $class = shift;
    my $link  = shift;
    my $this  = {};
    bless($this,$class);
    $this->{"site"} = $link;
    return $this;
}

1;

И код, который я использую для проверки функциональности:


use Link;

tie my $var,"Link","http://somesite.com";
$var->print_method;

При запуске сценарий завершится со следующей ошибкой: Невозможно вызвать метод "print_method" без ссылки на пакет или объект в строке 4 tietest.pl..

Если я правильно понимаю его сообщение, $var->print_method разрешается в некоторую строку, для которой вызывается метод print_method. Как я могу извлечь выгоду из tie, но при этом использовать переменную как объект?

РЕДАКТИРОВАТЬ: немного поэкспериментировав, я обнаружил, что если я верну $self при выборке, я могу вызвать методы, однако выборка не вернет адрес.

РЕДАКТИРОВАТЬ 2: монахи perl предоставили мне решение: связанный. linked вернет ссылку на объект VARIABLE .

Комбинируя связанные с моими методами, я могу добиться всего, чего хотел.


person Geo    schedule 07.02.2009    source источник


Ответы (2)


Галстук — неподходящий инструмент для этой работы. Связи используются, когда вам нужен тот же интерфейс, что и у обычных типов данных, но вы хотите настроить работу операций. Поскольку вы хотите получить доступ к строке и сохранить ее так же, как это уже делает скаляр, tie ничего для вас не делает.

Похоже, вам нужен модуль URI или его подкласс и, возможно, некоторая перегрузка.

Если вам действительно нужно это сделать, вам нужно использовать правильную переменную. связь связывает указанную вами переменную с указанным вами классом, но это все равно нормальный скаляр (а не ссылка). Вы должны использовать объект, который он возвращает, если вы хотите вызывать методы:

my $secret_object = tie my($normal_scalar), 'Tie::Class', @args;
$secret_object->print_method;

Вы также можете получить секретный объект, если у вас есть только связанный скаляр:

my $secret_object = tied $normal_scalar;

У меня есть целая глава о галстуке в Mastering Perl.

person brian d foy    schedule 07.02.2009

Я предлагаю создать обычный Perl-объект, а затем перегрузить строковое преобразование. Вы теряете возможность сохранять значение посредством присваивания, но сохраняете возможность получить значение, распечатав объект. Как только вы захотите вызывать методы напрямую, возможно, вам нужен объект.

package Link;

use strict;
use Carp;

use overload
(
  '""'      => sub { shift->site },
   fallback => 1,
);

sub new 
{
  my $class = shift;

  my $self = bless {}, $class;

  if(@_)
  {
    if(@_ == 1)
    {
      $self->{'site'} = shift;
    }
    else { croak "$class->new() expects a single URL argument" }
  }

  return $self;
}

sub site
{
  my $self = shift;
  $self->{'site'} = shift  if(@_);
  return $self->{'site'};
}

sub print_method
{
  my $self = shift;
  print $self->site, "\n";
}

1;

Пример использования:

use Link;

my $link = Link->new('http://somesite.com');

print $link, "\n";   # http://somesite.com
$link->print_method; # http://somesite.com

Если вы действительно хотите, чтобы присваивание тоже работало, вы можете комбинировать обычный объект с перегруженной строкой (Link, выше) с tie:

package LinkTie;

use strict;
use Link;

sub FETCH
{
  my $this = shift;
  return $this->{'link'};
}

sub STORE
{
  my($self, $site) = @_;
  $self->{'link'}->site($site);
  return $site;
}

# XXX: You could generalize this delegation with Class::Delegation or similar
sub print_method
{
  my $self = shift;
  print $self->{'link'}->print_method;
}

sub TIESCALAR
{
  my $class = shift;
  my $self = bless {}, $class;
  $self->{'link'} = Link->new(@_);
  return $self;
}

1;

Пример использования:

tie my $link,'LinkTie','http://somesite.com';
print $link, "\n";   # http://somesite.com
$link->print_method; # http://somesite.com

$link = 'http://othersite.com';

print $link, "\n";   # http://othersite.com
$link->print_method; # http://othersite.com

Это все довольно отвратительно, и пройти долгий путь, чтобы получить сомнительную возможность присваивать что-то, для чего вы также можете вызывать методы и также печатать как есть. Стандартный объект URI со строкой, вероятно, является лучшим выбором.

person Community    schedule 07.02.2009
comment
да, но назначение ему не будет иметь эффекта, который я ищу. То, что я спросил, невозможно? - person Geo; 07.02.2009