在Perl中初始化对象

时间:2010-08-27 15:30:26

标签: perl memory oop package

所以,我有点像perl newb。虽然我有一些更复杂的事情,但我突然遇到了障碍,无法弄清楚wtf是错误的代码。我已经大大简化了它,它只是一小段代码。

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并得到以下输出

  

通过课堂访问:
  通过main访问:asdfa

我也收到警告

  

使用未初始化的值   连接(。)或Test.pl中的字符串   第12行(#1)       (W未初始化)使用未定义的值,就好像它已经存在一样       定义。它被解释为“”或0,但也许这是一个错误。       要禁止此警告,请为变量分配定义的值。

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

3 个答案:

答案 0 :(得分: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中编写模块化代码是一种更清晰的方式。

答案 1 :(得分: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是一本很棒的书。

答案 2 :(得分:0)

子日志中的

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