我的直觉说这是一个非常糟糕的主意,但是我无法确定一个具体的问题。接下来是使用UNIVERSAL包中的AUTOLOAD子例程非常原始的mixin / traits实现。关于XY problem答案,正确的答案是使用Moo,但是与我交谈的人出于某种毫无意义的原因不希望使用非Core模块,我想说服他们这种方法,而从技术上讲,这是一个坏主意,所以我需要技术上的理由,以使这种方法除了让人感到古怪之外,还不是一个好主意。
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
{
package UNIVERSAL;
sub with {
my ($class, @mixins) = @_;
our %mixin_map;
push @{ $mixin_map{$class} }, @mixins;
}
sub AUTOLOAD {
our $AUTOLOAD;
# Never propagate DESTROY methods
return if ($AUTOLOAD =~ /::DESTROY$/);
my ($class, $method) = $AUTOLOAD =~ /(.*)::(.*)/;
my @mixins = do {
our %mixin_map;
@{ $mixin_map{$class} };
};
for my $mixin (@mixins) {
# find the mixin/trait that supports this method
if (my $sub = $mixin->can($method)) {
{ #install the mixin's method in the class
no strict "refs";
*{ "$class::$method" } = $sub;
}
# call this class's method with the original arguments
return $class->can($method)->(@_);
}
}
use Carp;
Carp::croak("could not find a method $method for class $class\nlooked in:", join ", ", @mixins);
}
}
{
package T;
T->with(qw( Init Misc ));
}
{
package A;
A->with( qw/Init Helper/ );
}
{
package Init;
sub new {
my ($class, $hParams) = @_;
return bless {}, $class;
}
}
{
package Helper;
sub foo {
my ($self) = @_;
print "foo here\n";
}
}
{
package Misc;
sub something {
my ($self) = @_;
print "and more...\n";
}
}
{
package main;
my $t = T->new;
my $a = A->new;
$a->foo;
$t->something;
eval {
$t->foo;
1;
} or do {
print "yay! calling foo on t failed\n";
};
eval {
$a->something;
1;
} or do {
print "yay! calling somehting on a failed\n";
};
}
最佳答案
问题:
安装AUTOLOAD
时,应创建相应的can
。
中断所有现有的UNIVERSAL::AUTOLOAD
。
将with
添加到所有类。
被大多数其他AUTOLOAD
破坏。
有些是可修复的,有些则不是。但这表明这是多么复杂和脆弱。而且完全没有必要。 with
可以导入方法,也可以简单地将类添加到@ISA
。
关于perl - 为什么不应该在UNIVERSAL包中创建AUTOLOAD子例程?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28729542/