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

时间:2023-01-17 00:07:25

I've just started to learn about tie. I have a class named Link which I would like to do the following thing:

我刚刚开始学习领带。我有一个名为Link的类,我想做以下事情:

  • if fetched, return the link's address
  • 如果已获取,则返回链接的地址

  • if stored, store the new address
  • 如果存储,则存储新地址

  • be able to call methods on it
  • 能够调用它上面的方法

So far, my code is :

到目前为止,我的代码是:


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;

And the code I'm using to check the functionality is:

我用来检查功能的代码是:


use Link;

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

When ran, the script will terminate with the following error: Can't call method "print_method" without a package or object reference at tietest.pl line 4..

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

If I understand its message correctly, $var->print_method resolves to some string upon which the method print_method is called. How could I benefit from tie, but also use the variable as an object?

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

EDIT: after experimenting a bit,I found out that if I return $self on fetch , I can call the methods , however , fetch won't return the address .

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

EDIT 2:the perl monks supplied me the solution : tied . tied will return a reference to the object VARIABLE .

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

By combining tied with my methods , I can accomplish everything I wanted .

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

2 个解决方案

#1


Tie is the wrong tool for this job. You use ties when you want the same interface as normal data types but want to customize how the operations do their work. Since you want to access and store a string just like a scalar already does, tie doesn't do anything for you.

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

It looks like you want the URI module, or a subclass of it, and perhaps some overloading.

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

If you really need to do this, you need to use the right variable. The tie hooks up the variable you specify to the class you specify, but it's still a normal scalar (and not a reference). You have to use the object it returns if you want to call methods:

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

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

You can also get the secret object if you only have the tied scalar:

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

my $secret_object = tied $normal_scalar;

I have an entire chapter on tie in Mastering Perl.

我有一整章关于掌握Perl的关系。

#2


I suggest making a normal Perl object and then overloading stringification. You lose the ability to store a value through assignment, but retain the ability to get the value out by printing the object. Once you start wanting to call methods directly, an object is probably what you want.

我建议制作一个普通的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;

Example usage:

use Link;

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

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

If you really, really want assignment to work too, you can combine a normal object with overloaded stringification (Link, above) with tie:

如果你真的,真的希望赋值也可以工作,你可以将一个普通的对象与重载的字符串化(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;

Example usage:

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

This is all quite hideous and a long way to go just to get the dubious ability to assign to something that you can also call methods on and also print as-is. A standard URI object with stringification is probably a better bet.

这一切都非常可怕,并且还有很长的路要走,只是为了获得可疑的能力,分配给你也可以调用方法的东西,并按原样打印。具有字符串化的标准URI对象可能是更好的选择。

#1


Tie is the wrong tool for this job. You use ties when you want the same interface as normal data types but want to customize how the operations do their work. Since you want to access and store a string just like a scalar already does, tie doesn't do anything for you.

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

It looks like you want the URI module, or a subclass of it, and perhaps some overloading.

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

If you really need to do this, you need to use the right variable. The tie hooks up the variable you specify to the class you specify, but it's still a normal scalar (and not a reference). You have to use the object it returns if you want to call methods:

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

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

You can also get the secret object if you only have the tied scalar:

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

my $secret_object = tied $normal_scalar;

I have an entire chapter on tie in Mastering Perl.

我有一整章关于掌握Perl的关系。

#2


I suggest making a normal Perl object and then overloading stringification. You lose the ability to store a value through assignment, but retain the ability to get the value out by printing the object. Once you start wanting to call methods directly, an object is probably what you want.

我建议制作一个普通的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;

Example usage:

use Link;

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

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

If you really, really want assignment to work too, you can combine a normal object with overloaded stringification (Link, above) with tie:

如果你真的,真的希望赋值也可以工作,你可以将一个普通的对象与重载的字符串化(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;

Example usage:

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

This is all quite hideous and a long way to go just to get the dubious ability to assign to something that you can also call methods on and also print as-is. A standard URI object with stringification is probably a better bet.

这一切都非常可怕,并且还有很长的路要走,只是为了获得可疑的能力,分配给你也可以调用方法的东西,并按原样打印。具有字符串化的标准URI对象可能是更好的选择。