绑定标量的构造函数

发布于 2024-10-16 03:22:07 字数 806 浏览 2 评论 0原文

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

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();

我假设这不起作用,因为领带无法在副本中幸存(我读过在文档中的某处),是否根本没有办法做到这一点?

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

If I were to have a simple tied scalar class that increments every time it is read I could do that like this:

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;

However to create a counter variable I have to use tie. I could create one counter and export it. But what I really want to do is make it look OO. It seems that I could create a new method like this:

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

  tie $counter, $class;

  return $counter;
}

then in my main script get two counters by doing:

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

I am assuming this doesn't work because a tie doesn't survive a copy (I read that in the docs somewhere), is there simply no way to do this?

NB. I know it is only a matter of style, but it would LOOK more correct to the eye.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

各自安好 2024-10-23 03:22:07

Tie 魔法不会在赋值过程中进行,因为它适用于变量本身,而不是它包含的值。您有几个选择:

返回引用:

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]。原因是 @_ 的元素是参数列表的别名,因此它的工作方式就像您在 tie 中键入 my $counter 一样 行。


最后,虽然您的示例非常清晰并遵循最佳实践,但本着 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;

但是您失去了通过赋值重置计数器的能力。您可以向 Counter 添加一个子集 {$_[0][0] = $_[1]} 方法。

Tie magic is not carried across assignment because it applies to the variable itself, not the value it contains. You have a few options:

Returning a reference:

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

my $counter = Counter->new;

say $counter;

Assigning to a glob:

our ($counter);

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

say $counter;

Or you could pass the variable into the constructor:

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

Counter->new(my $counter);

say $counter;

You can even make a constructor that works with both methods:

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

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

Counter->new(my $lexical);

In the last two examples, tie is passed $_[0] directly. The reason for this is that the elements of @_ are aliases to the argument list, so it works as if you had typed the my $counter in the tie line.


And finally, while your example is very clear and follows best practices, in the spirit of TIMTOWTDI, you could write your entire class like this:

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

One last thing to mention. While your question is about tied variables, you can also use overloading to achieve this:

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

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

say $counter;

But you loose the ability to reset the counter via assignment. You could add a sub set {$_[0][0] = $_[1]} method to Counter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文