2010-10-10 69 views
2

我有一个模块正在处理中。我设置了这样几个属性:OO-Perl别名类属性

$self->{FOO}; 
$self->{BAR}; 
$self->{FOOBAR}; 

而且,我想使用AUTOLOAD来帮助创建访问这些属性的方法。例如,$foo->Bar()返回值$self->{BAR}。没问题。一切都是标准的。

现在,我想创建别名方法。例如,如果有人说$obj->Fu();,我会返回$self->{FOO}。我想要做的是创建一个指向与$self->{FOO}相同的内存位置的$self->{FU}。这样,当我设置值$self->{FOO}时,$self-{FU}也被设置。这样,我无需在AUTOLOAD工作方式上进行各种更改,或者在设置$self->{FOO}时记得设置$self->{FU}

任何简单的方法呢?

回答

10

是的,使用Moose,而不是试图在散列 键之间进行明确的映射。编写您自己的存取或使用AUTOLOAD,是没有必要的,有 高得多的错误几率:

package MyClass; 

use Moose; 
use MooseX::Aliases; 

has foo => (
    is => 'rw', isa => 'Str', 
    alias => 'fu', 
); 
has bar => (
    is => 'rw', isa => 'Str', 
); 
__PACKAGE__->meta->make_immutable; 
no Moose; 
1; 

package main; 
use strict; 
use warnings; 
use MyClass; 
my $obj = MyClass->new; 
$obj->foo("value"); 
$obj->fu("a new value"); 

# prints "foo has the value 'a new value'" 
print "foo has the value '", $obj->foo, "'\n"; 
+0

我知道驼鹿,但问题是穆斯不是标准Perl安装的一部分,并且将模块下载到许多我使用的系统是不可能的。我必须让SysAdmin来做到这一点。 – 2010-11-10 03:11:37

+1

@David:围绕这个问题有办法。请参阅http://www.shadowcat.co.uk/blog/matt-s-trout/but-i-cant-use-cpan/。 – Ether 2010-11-10 05:07:25

4

我会建议Moose在你在做什么,但最简单的方式来完成你在做什么问大概是这样的:

sub Fu { shift->Foo(@_) } 

这样,如果Foo被自动加载与否并不重要。

+0

这很容易,语法看起来不那么糟糕。但是,对于很多方法来说,这样做实际上是相当多的工作,并且当你有新的方法或别名时修改代码。 – 2010-10-11 18:30:50

0

非Moose解决方案是在符号表中创建一个别名。这不是一件常见的事情,我怀疑无论你想要做什么都有更好的方式,麋鹿或其他。如果您可以通过更好的设计或界面来避免这种情况发生,那么请不要使用这些设备或界面,而这往往是这类事情的上级解决方案。

在这个AUTOLOAD例程中,我看一个%Aliases散列来找出其他我必须定义的方法。当我有别名时,我在符号表中做了适当的别名。这是一个有点难看,但它避免了在调用堆栈中添加另一种实际的方法:

#!perl 

use 5.010; 

{ 
package SomeClass; 
use Carp; 
use vars qw($AUTOLOAD); 

sub new { 
    return bless { 
     map { $_, undef } qw(FOO BAR FOOBAR) 
     }, $_[0]; 
    }; 

my %Aliases = (
    FOO => [ qw(fu) ], 
    ); 

sub AUTOLOAD { 
    our $method = $AUTOLOAD; 
    $method =~ s/.*:://; 

    carp "Autoloading $method"; 

    { 
    no strict 'refs'; 
    *{"$method"} = sub { 
     @_ > 1 
       ? 
      $_[0]->{"\U$method"} = $_[1] 
       : 
      $_[0]->{"\U$method"} 
     }; 

    foreach my $alias (@{ $Aliases{"\U$method"} }) { 
     *{"$alias"} = *{"$method"}; 
     } 

    goto &{"$method"}; 
    } 

    } 

sub DESTROY { 1 } 
} 

my $object = SomeClass->new; 

$object->foo(5); 

say "Foo is now ", $object->foo; 
say "Foo is now ", $object->foo(9); 
say "Fu is now ", $object->fu; 
say "Fu is set to ", $object->fu(17); 
say "Foo is now ", $object->foo; 

现在foofu访问同一件事:

Foo is now 5 
Foo is now 9 
Fu is now 9 
Fu is set to 17 
Foo is now 17 
+0

如果有人调用'fu'_before_调用'foo',这将无法正常工作,因为别名方法仅在实际方法被调用时才会创建。 – cjm 2010-10-11 18:40:49

+0

我的特定代码不这样做,但要做到这一点并不难。 – 2010-10-11 19:00:33