Современный Perl: как реализовать методы Redispatching в AUTOLOAD ()? - PullRequest
4 голосов
/ 25 февраля 2011

Чувствую себя слабым в теме ОО, я пытаюсь стать лучше с Современная книга Perl . О заданной теме я нашел в книге следующий пример:

package Proxy::Log; 

sub new
{
    my ($class, $proxied) = @_;
    bless \$class, $proxied;
}

sub AUTOLOAD
{
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    Log::method_call( $name, @_ );
    my $self = shift;
    return $$self->$name( @_ );
}

Этот код - простой или рабочий пример?

Я не понимаю, как я могу его использовать, где и что он должен регистрировать и как я должен создать объект (что должно попасть в $proxied)?

Я добавил несколько строк, чтобы протестировать его, но не получил функции AUTOLOAD:

package main;

my $tst = Proxy::Log->new();
say $tst->AnyKindOfSub();

Надеюсь, вы могли бы привести меня к какому-то рабочему коду. Я думаю, у меня есть идея, как работает замыкание и автозагрузка, но я здесь немного застрял.

Ответы [ 2 ]

8 голосов
/ 25 февраля 2011

Как заметил bvr, вы перевернули свои аргументы, чтобы благословить конструктор.Так что, хотя это и является непосредственной проблемой для вашего кода, при написании методов повторной отправки важно учитывать использование синтаксиса goto &sub для стирания стекового кадра вызова AUTOLOAD:

sub AUTOLOAD
{
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    Log::method_call( $name, @_ );
    my $self = shift;
  # return $$self->$name( @_ );   # instead of this, use the following:
    unshift @_, $$self;           # setup argument list
    goto &{ $$self->can($name) }  # jump to method
}

Если пересылкаМетод использует встроенную функцию caller для чего-либо (установка методов, локализация переменных, Carp сообщение об ошибке ...), тогда эта техника будет поддерживать правильную работу caller.Использование исходной строки return $$self->$name(@_) всегда сообщало бы, что caller была последней строкой подпрограммы AUTOLOAD, что, в свою очередь, могло бы стать источником труднодоступных ошибок.

Если вы хотите улучшитьНемного сообщив об ошибке, вы могли бы написать последнюю строку как:

 goto &{ $$self->can($name) or Carp::croak "no method '$name' on $$self" };

Что предполагает, что пакет Carp был загружен.

4 голосов
/ 25 февраля 2011

Я думаю, что пример переключил bless параметры в new из Proxy::Log. Вероятно, должно быть:

bless \$proxied, $class;

Найдите ниже функциональный пример, как это было задумано. Прокси-класс записывает журнал, а затем повторно отправляет вызов целевому объекту (класс Another в примере ниже).

package Proxy::Log;

sub new {
    my ($class, $proxied) = @_;
    bless \$proxied, $class;
}

sub AUTOLOAD {
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    warn "$name: @_";
    my $self = shift;
    return $$self->$name( @_ );
}

package Another;

sub new { 
    bless {}, $_[0];
} 

sub AnyKindOfSub {
    warn "Target called\n";
    return "Hello";
};


package main;

my $tst = Proxy::Log->new(Another->new);
say $tst->AnyKindOfSub();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...