gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 09:24:01 24 4
gpt4 key购买 nike

我一直在使用 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 的值,我是对的吗?

最佳答案

使用 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 sub 将被调用,并带有缺少的 sub 的参数。所请求子程序的完全限定名称在 $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 对象系统。

关于perl - Perl 中 AUTOLOAD 的默认参数是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17207111/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com