如何在绑定变量上调用方法?

时间:2009-02-07 18:29:14

标签: perl object tie

我刚刚开始了解 tie 。我有一个名为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;

运行时,脚本将以以下错误终止: 如果没有在tietest.pl第4行的包或对象引用,则无法调用方法“print_method”。

如果我正确理解了其消息, $var->print_method 会解析为调用 print_method 方法的字符串。我如何从tie中受益,还可以将变量用作对象?

编辑:经过一些实验,我发现如果我在fetch上返回$ self,我可以调用这些方法,但是,fetch不会返回地址。

编辑2:perl僧侣为我提供了解决方案:绑定。 tied将返回对象VARIABLE的引用。

通过结合我的方法,我可以完成我想要的一切。

2 个答案:

答案 0 :(得分:10)

Tie是这项工作的错误工具。当您需要与普通数据类型相同的接口但希望自定义操作的工作方式时,可以使用tie。由于您想要像标量一样访问和存储字符串,因此tie不会为您做任何事情。

看起来你想要URI模块或它的子类,也许还有一些重载。

如果您确实需要这样做,则需要使用正确的变量。 tie将您指定的变量挂钩到您指定的类,但它仍然是正常的标量(而不是引用)。如果要调用方法,则必须使用它返回的对象:

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

如果你只有绑定的标量,你也可以获得秘密对象:

my $secret_object = tied $normal_scalar;

我在Mastering Perl中有一整章关于平局。

答案 1 :(得分:9)

我建议制作一个普通的Perl对象然后overload进行字符串化。您失去了通过赋值存储值的功能,但保留了通过打印对象来获取值的功能。一旦你开始想直接调用方法,一个对象可能就是你想要的。

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对象可能是更好的选择。