2010-06-04 90 views
5

有人能告诉我为什么在这个非常小而平凡的例子中,main没有找到Class :: Accessor生成的方法吗?Perl Class ::访问失败,简单的例子 - 为什么?

的这几行代码失败,

perl codesnippets/accessor.pl 
Can't locate object method "color" via package "Critter" at 
codesnippets/accessor.pl line 6. 

看到代码:

#!/opt/local/bin/perl 
# The whole Class::Accessor thing does not work !! 

my $a = Critter->new; 
$a->color("blue"); 
$a->display; 
exit 0; 

package Critter; 
    use base qw(Class::Accessor); 
    Critter->mk_accessors ("color"); 

    sub display { 
     my $self = shift; 
     print "i am a $self->color " . ref($self) . ", whatever this word means\n"; 
    } 
+0

我只是想看到以类别::访问器::优雅和鼠标相同的行为。 – 2010-06-04 11:34:44

+0

请勿使用鼠标或C:A,请使用'Moose' – 2010-06-04 15:16:19

+0

请参阅[我的解决方案](http://stackoverflow.com/questions/2973549/perl-classaccessor-failure-trivial-example-why/2975492#2975492)例如“穆斯”中的一个例子。 – 2010-06-04 15:25:24

回答

3

FM给你很好的建议。需要在其他代码之前运行mk_accessors。另外,通常你会把Critter放在一个单独的文件中,并且use Critter加载模块。

这是可行的,因为use具有编译时间效果。做use Critter;和做BEGIN { require Critter; Critter->import; }是一样的。这保证你的模块的初始化代码在代码的其余部分编译之前运行。

将多个包放入一个文件是可以接受的。通常情况下,我会将相关对象的原型制作在一个文件中,因为它可以在我进行原型设计时保持一切便利。随着时间的推移,将文件分成不同的位也很容易。因此,我发现将多个包保存在一个文件中,并像使用它们一样处理它们的最佳方式是将包定义放在以真值结束的BEGIN块中。用我的方法,你的榜样将写成:

#!/opt/local/bin/perl 

my $a = Critter->new; 
$a->color("blue"); 
$a->display; 

BEGIN { 
    package Critter; 
    use base qw(Class::Accessor); 

    use strict; 
    use warnings; 

    Critter->mk_accessors ("color"); 

    sub display { 
     my $self = shift; 

     # Your print was incorrect - one way: 
     printf "i am a %s %s whatever this word means\n", $self->color, ref $self; 

     # another: 
     print "i am a ", $self->color, ref $self, "whatever this word means\n"; 

    } 

    1; 
} 
+0

我也不过的BEGIN块在当天晚些时候我发布这个问题,我现在会尝试。 我不想把类包文件作为单独的文件,因为我写一个perl程序,我希望把它分发作为一个Perl脚本,而无需告诉用户安装的所有类包文件分开,并设置其PERL5LIB变量 – 2010-06-07 01:56:12

+0

我也想知道为什么Critter-> new()正在工作,而不是$ a-> color(“blue”),但是你对“使用”内部工作的解释告诉我为什么函数(例如new())从基类C:A继承而来。 – 2010-06-07 02:03:15

8

你的代码是乱序。如果你想要color访问器可用,你需要在之前调用mk_accessors你创建你的对象,并开始做它的东西。例如:

package Critter; 
use base qw(Class::Accessor); 
Critter->mk_accessors("color"); 

sub display { 
    my $self = shift; 
    print $self->color, ' ', ref($self), "\n"; 
} 

package main; 
my $c = Critter->new; 
$c->color("blue"); 
$c->display; 

更常见的是,Critter代码将其自身的模块(Critter.pm)中,且所有的mk_accessor魔术会发生,当你的主要脚本运行use Critter - 你的脚本开始与Critter行之有效前和Varmint对象。

+1

或者,可以将包声明一个BEGIN块以确保它在尝试实例化对象之前运行。 – Ether 2010-06-04 16:08:44

+0

是的,代码是不合理的,它的目的是让主要部分在开始时很容易看到,并且将实现和所有类的东西埋在文件底部。 它不是一个单独的文件,因为我写一个perl程序,我希望把它分发作为一个Perl脚本,而无需告诉用户安装的所有类包文件分开,并设置其PERL5LIB变量 – 2010-06-07 01:53:28

2

我只是想为您提供更好的解决方案 - 如果解不欢迎随时downvote这个被遗忘,但是C :: A是真是一个糟糕的主意这个时代,使用Moose

package Critter; 
use Moose; 

has 'color' => (isa => 'Str', is => 'rw'); # Notice, this is typed 

sub display { 
    my $self = shift; 
    printf (
     "i am a %s %s whatever this word means\n" 
     , $self->color 
     , $self->meta->name 
    ); 
} 

package main; 
use strict; 
use warnings; 

my $c = Critter->new; # or my $c = Critter->new({ color => blue }); 
$c->color("blue"); 
$c->display; 
+0

或鼠标,如果你关心启动时间。 – MkV 2010-06-04 18:31:32

+0

虽然Moose在默认的更为保守的linux发行版(比如centos)中是不可用的,并且使用C:A进行了快速测试。但我现在看到穆斯其实在那里,所以我可以使用它。由于我的目的是制作一个易于分发的perl脚本,因此我尽量避免使用所有现代和/或花哨的模块,以便脚本可以在任何地方运行,而无需直接从cpan获取模块 – 2010-06-07 01:59:18

+0

'use Moose'和'Module ::安装“ - 可以将外部软件包添加到模块中。即使没有'Module :: Install','Moose'可能很可能在任何体面的Perl用户的系统上。这也将使编程使用perl更加愉快。 – 2010-06-08 15:10:20

相关问题