即使在对象被销毁后,状态变量仍然存在

State variable persists even after object has been destroyed

我在模块方法中有一个“state”变量来缓存该方法生成的第一个值。问题是即使在对象被销毁并且创建了一个全新的对象并使用该方法后,该方法仍继续使用状态变量值。

这看起来确实像是 perl 状态变量实现中的错误,但我不确定。我知道我可以创建一个模块属性来缓存值,但我想在方法级别进行。这是一个例子:

package MyTest;
use 5.010001;
use strict;

sub new {
    my $class = shift;
    return bless {}, $class;
}

sub generate_id {
    my $self = shift;
    state $generated_id;
    
    return $generated_id
        if defined $generated_id;
    
    $generated_id = "XYZ-" . int(rand 10000);
    return $generated_id;
}

sub DESTROY {
    say "Object has been destroyed";
}

1;

这是调用它的脚本。正如您将看到的,“generate_id”方法第一次生成的值将继续返回,即使在“$c”变量超出范围并生成新变量后也是如此。这不是一个错误吗?我认为在对象超出范围后,所有变量(包括状态变量)以及方法内容都会被销毁。

# Script.pl
use MyTest;

{
  my $id_gen = MyTest->new();
  say $id_gen->generate_id();
}

{
  my $id_gen = MyTest->new();
  say $id_gen->generate_id();
}

{
  my $id_gen = MyTest->new();
  say $id_gen->generate_id();
}

我得到:

XYZ-6345
Object has been destroyed
XYZ-6345
Object has been destroyed
XYZ-6345
Object has been destroyed

Perl 5 没有真正的方法,generate_id 只是一个子方法,它以对象实例作为第一个参数调用。 因此,状态变量 $generated_id 为整个 运行 程序缓存 - 并且将包含您调用它的任何实例的相同值。 您可能想为生成的 ID 使用属性。

是的,这就是 state 的重点。变量保留其状态。线索就在名字里。

I thought all variable would be destroyed (including state variables) as well as method content after an object goes out of scope.

当方法被销毁时,变量会超出范围,是的,但是当 object 被销毁时,方法不会被销毁。该方法在 class 被销毁时被销毁。 classes 在程序退出之前不会真正被销毁。 (您可以通过大量手动符号 table 破解来完成此操作,但我不建议这样做。)

听起来你想要的是这样的:

sub generate_id {
    my $self = shift;
    $self->{generated_id} ||= "XYZ-" . int(rand 10000);
}