2010-08-27 155 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