【问题标题】:Perl: How can I call object methods inside END {} without warning?Perl:如何在没有警告的情况下调用 END {} 内的对象方法?
【发布时间】:2009-12-16 13:43:15
【问题描述】:
package JustTesting;
use strict;
use warnings;

sub new {
    my $self = {};
    bless($self, shift);
    END { $self->goodbye() };
    return $self;
}

sub goodbye {
    print "Goodbye.\n";
}

package main;
my $this = JustTesting->new();

输出:

变量“$self”不会在 ./test 第 10 行保持共享。
再见。

显然它有效,我可以在 END 块内使用 no warnings 抑制警告。但我想知道是否有更好的方法 如何做到这一点。

我尝试使用这样的匿名子:

my $cleanup = sub { $self->goodbye() };
END { $cleanup->() };

然后像这样:

END { sub { $self->goodbye() }->() };

但我总是收到同样的警告。

【问题讨论】:

    标签: perl perl-module


    【解决方案1】:

    您很可能想要DESTROY 而不是END。另见the section on destructors in perltoot。

    package JustTesting;
    use strict;
    use warnings;
    
    sub new {
        my $self = {};
        bless($self, shift);
        return $self;
    }
    
    sub goodbye {
        print "Goodbye.\n";
    }
    
    sub DESTROY {
        my ($self) = @_;
        $self->goodbye()
    };
    
    
    package main;
    {
        say "entering scope";
        my $this = JustTesting->new();
        say "leaving scope";
    }
    say "left scope";
    

    输出:

    进入范围 离开范围 再见。 左范围

    【讨论】:

    • 是的,这就是我想要的。谢谢!现在我可能应该去买一本关于面向对象设计方法的书,然后在接下来的六个月左右的时间里用它来敲我的额头。
    【解决方案2】:

    仅供参考,我附上了Moose 的daxim 的正确answer 版本。

    use 5.012;
    use warnings;
    
    {
        package JustTesting;
        use Moose;
        use namespace::clean -except => 'meta';
    
        sub goodbye { say "Goodbye." }
    
        sub DEMOLISH {
            my ($self) = @_;
            $self->goodbye;
        }
    }
    
    {
        say "entering scope";
        my $this = JustTesting->new();
        say "leaving scope"; 
    }
    
    say "left scope";
    

    注意destructor 的DEMOLISH 子例程的使用。

    注意。您会发现 DESTROY 仍然有效,但 DEMOLISH 是正确的 Moosey 方式。

    /I3az/

    【讨论】:

      【解决方案3】:

      首先,请参阅my() Scoped Variable in Nested Subroutines 以获得解释。

      其次,我认为您应该使用DESTROY 或帮助器类,具体取决于您要实现的目标。

      【讨论】:

        【解决方案4】:

        警告的原因是因为即使它看起来不像,perl 一个END 块等同于声明一个常规(命名)子,并且一个命名子的行为在内部声明另一个子不是你想要的——END 块内的$self 将在sub new 中绑定到$self,这是调用new 的第一次,它会在程序的剩余生命周期中继续看到相同的值——创建的第一个实例。第一个实例将有一个由END 块持有的引用,并且在程序结束之前不会被销毁,并且任何后面的实例根本不会调用END 块。

        与命名 subs 不同,匿名 subs 没有这个问题,因为每次遇到它们的定义时都会重新构造它们,因此它们关闭的任何变量都尽可能晚地绑定,并捕获您真正想要的值.

        当其他人已经告诉您您想要的是 DESTROY 时,这是一个相当长的解释,但我想您可能想知道您编写的代码实际上发生了什么。

        【讨论】:

          【解决方案5】:

          在调用END 块时,$cleanup 已经被释放。要对变量进行任何操作,您应该改用析构函数。

          请参阅perldoc perlobj 上的“析构函数”。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-12-22
            • 2021-11-22
            • 1970-01-01
            • 2021-08-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多