Perl中AUTOLOAD的默认参数是什么?

时间:2013-06-20 06:56:38

标签: perl oop autoload

我一直在玩AUTOLOAD来在Perl中创建我的访问者,我遇到了这种混乱(我已经搜索过google和perldoc)。

我有这段代码:

package Class;
sub new {
..code for constructor here.
}

sub AUTOLOAD {
 my $name= shift;
 print $name;
}

但是,当我执行以下操作时:my $a=Class->new;自动加载子例程仍然执行,并打印Class=HASH(some weird number);

我认为AUTOLOAD仅在存在未定义的方法或子例程时运行?

我也这样做了:

my $class = our $AUTOLOAD;

print $class #prints ::DESTROY

当我假设没有未定义的函数传递时DESTROY是$ AUTOLOAD的值时,我是对的吗?

1 个答案:

答案 0 :(得分:7)

使用Autoload本质上很困难。如果你想要一个为你提供访问器的实体对象系统,那么请使用Moose,Mouse,Moo ,或者只是遍历你的字段并自己安装访问者:

BEGIN {
  my @fields = qw/foo bar baz/;
  for my $field (@fields) {
    no strict 'refs';
    # install a closure in the package stash.
    *{ __PACKAGE__ . "::" . $field } = sub {
      my $self = shift;
      $self->{$field} = shift if @_;
      return $self->{$field};
    };
  }
}

如果一个可以AUTOLOAD遇到未定义方法的类,则使用缺失子的参数调用AUTOLOAD子。请求子的完全限定名称在$AUTOLOAD包变量中传递。

典型的Autoload sub看起来像:

use Carp;

my %fields_allowed = map {$_ => 1} qw/foo bar baz/;

sub AUTOLOAD {
  my $field = our $AUTOLOAD;
  $field =~ s/.*:://; # strip the package name
  $fields_allowed{$field}
    or croak qq(Can't locate object method $field via package "@{[__PACKAGE__]}");
  my $self = shift;
  $self->{$field} = shift if @_;
  return $self->{$field};
}

还有两个问题:

  • 当对象的引用计数降为零时,或者当线程终止时,如果对象提供了DESTROY方法,则会调用该方法。我们可以通过提供空实施来阻止DESTROY的自动加载:sub DESTROY {}
  • 我们可以询问任何对象是否可以执行某种方法,例如say "Good dog" if $dog->can("roll")。因此,我们必须覆盖can以支持我们的自动加载。 can方法对于安全的鸭子打字非常有用。每个对象都继承自UNIVERSAL,它为canisa提供默认实现。

can的合同是它采用方法的名称。当对象无法执行该方法时,它将返回undef,如果可以,则返回该方法的代码引用。合适的实施方式是

sub can {
  my ($self, $name) = @_;

  # check if it's a field of ours
  if ($fields_allowed{$name}) {
    return sub {
      my $self = shift;
      $self->{$name} = shift if @_;
      return $self->{$name};
    };
  }

  # Ask SUPER implementation of can if we can do $name
  if (my $meth = $self->SUPER::can($name)) {
    return $meth;
  }
  return; # no method found
}

我们现在可以将AUTOLOAD简化为

sub AUTOLOAD {
  my $field = our $AUTOLOAD;
  $field =~ s/.*:://; # strip the package name
  my $code = $self->can($field)
    or croak qq(Can't locate object method $field via package "@{[__PACKAGE__]}");
  goto &$code; # tail call; invisible via `caller()`.
}

要想做到这一点,这很复杂。结论:不要使用Autoload,因为您认为它可能不那么重要。它永远不会。它对于实现代理模式非常有用,但这有点高级。

在深入了解Perl独特而奇特的功能之前,我恳请您使用OO基础知识和Moose对象系统。