我的直觉说这是一个非常糟糕的主意,但是我无法确定一个具体的问题。接下来是使用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/

10-10 07:44