Perl:将Coderef分配给没有符号表的方法
基于前面关于Class::Struct vs Object::Accessor的查询,我想找到从对象构造函数中的coderefs分配包子的最佳方法。嘿,我已经记下了OO属性,让我们来看看方法:) 请注意,我说的是“最佳”方式。我已经找到了两种方法,这两种方法似乎也是类似问题的流行答案,但它们分别需要避开严格的警告和警告 请注意,该示例使类用户能够在构造时重写格式化方法。可怜的例子,但你明白了。为了先发制人地反驳OO纯粹主义者,这在我的特定设计中比让类用户用自己的重写版本将其子类化更有意义 以下是我的两次尝试:Perl:将Coderef分配给没有符号表的方法,perl,oop,class,object,methods,Perl,Oop,Class,Object,Methods,基于前面关于Class::Struct vs Object::Accessor的查询,我想找到从对象构造函数中的coderefs分配包子的最佳方法。嘿,我已经记下了OO属性,让我们来看看方法:) 请注意,我说的是“最佳”方式。我已经找到了两种方法,这两种方法似乎也是类似问题的流行答案,但它们分别需要避开严格的警告和警告 请注意,该示例使类用户能够在构造时重写格式化方法。可怜的例子,但你明白了。为了先发制人地反驳OO纯粹主义者,这在我的特定设计中比让类用户用自己的重写版本将其子类化更有意义 以下是
use 5.014;
use autodie;
use strict;
use warnings;
package Account {
use base 'Object::Accessor';
sub new {
my ($type, %args) = @_;
my $self = bless { }, $type;
$self->mk_accessors(qw(
first_name last_name age_in_years activated
));
$self->first_name( $args{first_name } // 'Default First Name' );
$self->last_name( $args{last_name } // 'Default Last Name' );
$self->age_in_years($args{age_in_years} // 'Default Age in Years');
$self->activated( $args{activated } // 'Default Activated' );
{
# Stop skim reading and look here!
no warnings 'once';
*formatted = $args{formatted} || sub {
return 'Default formatting routine';
};
}
return $self;
}
}
my $account = Account->new;
say $account->formatted;
# Output: Default formatting routine
另一个:
use 5.014;
use autodie;
use strict;
use warnings;
package Account {
use base 'Object::Accessor';
sub new {
my ($type, %args) = @_;
my $self = bless { }, $type;
$self->mk_accessors(qw(
first_name last_name age_in_years activated
));
$self->first_name( $args{first_name } // 'Default First Name' );
$self->last_name( $args{last_name } // 'Default Last Name' );
$self->age_in_years($args{age_in_years} // 'Default Age in Years');
$self->activated( $args{activated } // 'Default Activated' );
{
# Stop skim reading and look here!
no strict 'refs';
*{'formatted'} = $args{formatted} || sub {
return 'Default formatting routine';
};
}
return $self;
}
}
my $account = Account->new;
say $account->formatted;
# Output: Default formatting routine
前一种方法应该在没有警告的情况下工作,但它不能工作,因为Perl认为我没有在任何地方使用它,并在运行时将其标记为警告。如果不规避严格的限制,后者就不起作用,这就是它应该做到的:)
我所做的只是将一个方法分配给用户提供的coderef。应该有一个简单的方法来做到这一点
请注意,定义调用用户定义的coderef的新sub也不起作用,因为无法从中访问词法%args
虽然我们分配包变量,但它不能执行SUB
避免逃离严厉警告的花园,最干净的方法是什么?见鬼,可能有一种方法可以使用Object::Accessor模块来实现这一点,我只是不知道。它可以存储在$self中:
$$self{formatted} = sub { ... };
或者放进一个词汇:
my $formatted = sub { 1; }; # Dummy sub for initial assignment
sub new
{
...
$formatted = sub { ... };
}
sub formatted { $formatted->(@_) }
或者只是忍受并没有严格的“裁判”。只要它是在一个小的,良好的控制块,就像你在上面所做的,我从来没有认为它是邪恶的。或者更确切地说,它是邪恶的,但它是一个小的、包含良好的。严格的
是为了能够在您想做您不想意外做的事情的特定代码中关闭它。特别是,如果你像现在这样做,在尽可能小的范围内。它的工作方式与C语言中的pragmas相同。它允许您“违反规则”,而不会在没有“规则”的情况下容易受到无数问题的攻击
但是,如果您不想关闭任何“规则”,那么您应该查看。具体而言,qualify_to_ref
将返回对符号的引用,以便在将其转换回符号(见下文)时不会触发报警
因此,对于您提供的代码,您可以执行以下操作:
*{ Symbol::qualify_to_ref( 'formatted' ) }
= $args{formatted}
|| sub { return 'Default formatting routine'; }
;
如果希望“格式化”为可自定义的每个对象方法,并且在每次构造函数调用(分配给package sub就可以了)时不重写整个包/类(即所有对象)的方法,则可以将subref分配给对象“私钥”并从普通方法调用它:
sub new {
my ($type, %args) = @_;
...
$self->{_formatted} = $args{formatted} // sub { 'default' };
}
sub formatted {
my ($self) = shift;
return $self->{_formatted}->($self,@_);
}
嗯,第一种方法可以很好地工作。我说的第一种方法将重新评估每个构造函数调用的匿名子函数对吗?如果是这样的话,我想我可以将默认的coderef存储在一个状态变量中,然后每次调用都分配它,理论上应该只分配实际的引用,而不是每次都重新评估整个匿名子对象。实际上,对于前一种方法来说是可行的,但调用语法魔术的OO方法都不能使用它,所以我现在要尝试你的第二个建议:)好的,在尝试了你建议的所有这些方法之后,我将坚持警告规避方法。不幸的是,当我只想禁用定义未使用符号的特定警告时,我禁用了所有警告。perldiag的文件非常密集;您知道该特定违规的具体警告类型是什么吗?谢谢你到目前为止的帮助。@Eric:谢谢,这正是我要找的。这里的问题不是它有“符号表黑客”功能;问题是,除非只有一个Account对象存在,否则代码就会被破坏。