Как я могу вызвать методы для связанной переменной? - PullRequest
5 голосов
/ 07 февраля 2009

Я только начал узнавать о галстуке . У меня есть класс с именем 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" без ссылки на пакет или объект в строке tietest.pl 4. .

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

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

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

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

Ответы [ 2 ]

10 голосов
/ 08 февраля 2009

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

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

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

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

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

my $secret_object = tied $normal_scalar;

У меня есть целая глава по связям в Мастеринг Perl .

9 голосов
/ 07 февраля 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 со строковым форматированием.

...