5

我刚刚开始学习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;

运行时,脚本将终止并出现以下错误: Can't call method "print_method" without a package or object reference at tietest.pl line 4. .

如果我正确理解它的消息,则解析为调用$var->print_method该方法的某个字符串。print_method我怎么能从 tie 中受益,同时也将变量用作对象?

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

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

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

4

2 回答 2

10

领带是这项工作的错误工具。当您想要与普通数据类型相同的接口但想要自定义操作如何工作时,您可以使用 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有一整章是关于 tie 的。

于 2009-02-07T21:32:14.040 回答
9

我建议制作一个普通的 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 对象可能是更好的选择。

于 2009-02-07T19:49:58.380 回答