2010-08-27 103 views
3

所以,我是一个Perl的新手。虽然我有更复杂的事情,但我突然遇到了障碍,无法弄清楚代码中的wtf是否有错。我简化了它,它只是一小段代码。在Perl中初始化一个对象

Test.pl

package Test; 

sub new { 
    my ($class) = shift; 
    my $self = { 
    _attr => "asdfa" 
    }; 
    bless $self, $class; 
    return $self; 
} 
sub log { 
    print "\nAccessed via class: ".$self->{_attr}; 
} 

process.pl

#!/usr/bin/perl 
do "Test.pl"; 
use strict; 
use warnings; 
use diagnostics; 

my($test) = new Test(); 
$test->log; 
print "\nAccessed via main: ".$test->{_attr}; 

我跑process.pl,我得到下面的输出

通过类来访问:
通过访问的主要:asdfa

我也得到警告

使用未初始化值的 连接(。)或字符串在Test.pl线12(1#) 使用 (W未初始化)一个未定义的值,好像它已经定义了 。它被解释为“”或0,但也许这是一个错误。 要抑制此警告,请将一个定义的值分配给您的变量。

所以问题是$ self实际上是未定义的。为什么,我不知道。这不是初始化对象的方式吗?

回答

6

对象实例作为方法的第一个参数传递。通常要做的是将其存储在一个名为$self变量,但Perl不设置此为你,你必须做你自己:

sub log { 
    my $self = shift; 
    print "\nAccessed via class: ".$self->{_attr}; 
} 

注意的是,虽然你已经定义strictwarnings您主代码,你还没有在test.pl这意味着$self默默创建一个未定义的值,而不是使用未声明的变量的编译错误。

此外,我会建议你把package Test到一个名为Test.pm文件,在文件的结尾自行添加一个真实的说明1;,并说use Test;,而不是do "test.pl"调用它。这是用Perl编写模块化代码的更简洁的方法。

+0

谢谢sooo多! – 2010-08-27 15:45:45

0

在子日志:

sub log{ 
    my $self = shift; 
    print "\nAccessed via class: ".$self->{_attr}; 
} 
3

我知道你已经接受了答案,但你有一些严重的问题与您的代码。

  • 把你的对象定义在文件中.pm不能代替.pl
  • use模块do荷兰国际集团库结束。
  • 间接对象符号可能导致错误,最好避免使用它。

我冒昧地修改代码,修改问题所需的小改动。

首先在MyTest.pm

package MyTest; # Changed name to avoid name conflicts. 
use strict;  # Always 
use warnings; 

sub new { 
    my $class = shift; 
    # Removed parens on $class, they put the assignment of shift's 
    # result into list context (which had no effect on the result, 
    # but it is also unnecessary). 

    my %defaults = (attr => 'asdfa'); 
    my %args = %defaults, @_; 
    # Assigns arguments and default values to %args, actual named 
    # args will override keys in defaults where they match;  

    my $self = {};  

    bless $self, $class; 

    while(my ($attr, $value) = each %args) { 
    $self->$attr($value); # Initialize each attribute in named arg hash. 
    } 

    return $self; 
} 

sub attr { 
    my $self = shift; 
    if(@_) { 
     $self->{_attr} = shift; 
    } 

    return $self->{attr} 
}  

sub log { 
    my $self = shift; # Get invocant 
    print "Accessed via class: ", $self->attr, "\n"; 
} 

process.pl

#!/usr/bin/perl 
use strict; 
use warnings; 
use diagnostics; 

use MyTest; 

my $test = MyTest->new(); # Direct call of object constructor 

$test->log; 

print "Accessed via main: $test->{_attr}\n"; # Violating encapsulation 
               # is generally a bad idea. 

如果你是做重OOP,可以考虑学习使用Moose。 Moose是一个功能强大,超现代的Perl对象系统,它增加了强大的功能并减少了样板代码。

如果您想了解 “经典” 的Perl OOP,在参阅perldoc(perlbootperltootperlobjperlbotperltooc)的教程都还不错。如果你想深入研究它,Damian Conway's Object Oriented Perl是一本很棒的书。

+0

感谢您花时间彻底解释所有问题。非常感谢。 – 2010-08-29 17:30:04