2010-10-10 90 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