2

如果我有一个简单的绑定标量类,每次读取时都会递增,我可以这样做:

package Counter;

use strict;
use warnings;

sub TIESCALAR {
  my $class = shift;
  my $value = 0;

  bless \$value, $class;

  return \$value;
}

sub FETCH {
  my $self = shift;

  my $value = $$self;

  $$self++;

  return $value;
}

sub STORE {
  my $self = shift;
  $$self = shift;
}

1;

但是,要创建一个计数器变量,我必须使用tie. 我可以创建一个计数器并将其导出。但我真正想做的是让它看起来OO。看来我可以创建这样的new方法:

sub new {
  my $class = shift;
  my $counter;

  tie $counter, $class;

  return $counter;
}

然后在我的主脚本中通过执行以下操作获得两个计数器:

my $counter1 = Counter->new();
my $counter2 = Counter->new();

我假设这不起作用,因为领带无法在副本中保留下来(我在某处的文档中读到),难道根本没有办法做到这一点吗?

注意。我知道这只是风格问题,但它看起来更正确。

4

1 回答 1

11

Tie magic 不会通过赋值进行,因为它适用于变量本身,而不是它包含的值。你有几个选择:

返回参考:

sub new {tie my $ret, ...; \$ret}

my $counter = Counter->new;

say $$counter;

分配给 glob:

our ($counter);

*counter = Counter->new; # same new as above

say $counter;

或者您可以将变量传递给构造函数:

sub new {my $class = shift; tie $_[0], $class}

Counter->new(my $counter);

say $counter;

您甚至可以创建一个适用于这两种方法的构造函数:

sub new {
    my $class = shift;
    tie $_[0] => $class;
    \$_[0]
}

our $glob; *glob = Counter->new;

Counter->new(my $lexical);

在最后两个示例中,tie$_[0]直接传递的。这样做的原因是 的元素@_是参数列表的别名,因此它的工作方式就像您my $counter在该tie行中键入了一样。


最后,虽然您的示例非常清晰并遵循最佳实践,但本着 TIMTOWTDI 的精神,您可以像这样编写整个类:

{package Counter;
    sub TIESCALAR {bless [0]}
    sub FETCH {$_[0][0]++}
    sub STORE {$_[0][0] = $_[1]}
    sub new {tie $_[1] => $_[0]; \$_[1]}
}

最后要提一件事。虽然您的问题是关于绑定变量,但您也可以使用重载来实现此目的:

{package Counter;
    use overload fallback => 1, '""' => sub {$_[0][0]++};
    sub new {bless [0]}
}

my $counter = Counter->new;  # overloading survives the assignment

say $counter;

但是您失去了通过分配重置计数器的能力。您可以将sub set {$_[0][0] = $_[1]}方法添加到Counter.

于 2011-02-05T04:43:19.423 回答