Perl: Как я могу вызвать методы объекта внутри END {} без предупреждения? - PullRequest
3 голосов
/ 16 декабря 2009
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.
До свидания.

Очевидно, это работает, и я могу подавить предупреждение с помощью no warnings внутри блока END. Но мне интересно, есть ли лучший способ как это сделать.

Я пытался использовать анонимную подписку, как это:

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

а затем вот так:

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

Но я всегда получаю одно и то же предупреждение.

Ответы [ 5 ]

22 голосов
/ 16 декабря 2009

Скорее всего, вы хотите DESTROY вместо END. Смотрите также раздел о деструкторах в 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";

Выход:

entering scope
leaving scope
Goodbye.
left scope
7 голосов
/ 21 июня 2010

Только для справки будущим читателям, я прикрепил Moose версию daxim , правильный ответ .

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";

Обратите внимание на использование подпрограммы DEMOLISH для деструктора .

NB. Вы обнаружите, что DESTROY все еще работает, но DEMOLISH - это правильный способ Moosey.

/ I3az /

4 голосов
/ 16 декабря 2009

Во-первых, см. my() Переменная Scoped во вложенных подпрограммах для объяснения.

Во-вторых, я думаю, вы должны использовать DESTROY или вспомогательный класс в зависимости от того, чего вы пытаетесь достичь.

3 голосов
/ 17 декабря 2009

Причина предупреждения в том, что, хотя это не похоже на perl, блок END для perl эквивалентен объявлению регулярного (именованного) подпрограммы и поведению именованного подпрограммы, объявленному внутри другая подпрограмма не то, что вам нужно - $self внутри блока END будет привязан к $self в sub new в первый раз, когда вызывается new, и будет продолжаться чтобы увидеть то же значение - самый первый созданный экземпляр - до конца жизни вашей программы. У первого экземпляра будет ссылка, хранящаяся в блоке END, и он не будет уничтожен до конца программы, а во всех последующих экземплярах этот блок END не будет вызываться вообще.

В отличие от именованных подпрограмм, анонимные подпрограммы не имеют этой проблемы, потому что они воссоздаются каждый раз, когда встречается их определение, поэтому любые переменные, которые они закрывают, связываются как можно позже, а значения, которые вы на самом деле хотите, фиксируются .

Это довольно длинное объяснение, когда другие уже сказали вам, что вместо этого вы хотите DESTROY, но я подумал, что вам, возможно, стоит узнать, что на самом деле происходит с написанным вами кодом.

1 голос
/ 16 декабря 2009

К тому времени, когда вызывается блок END, $ cleanup уже освобожден. Чтобы выполнить любую работу с переменной, вы должны использовать вместо нее деструктор.

См. "Деструкторы" в perldoc perltoot .

...