代码之家  ›  专栏  ›  技术社区  ›  Brad G

在Perl中初始化对象

  •  3
  • Brad G  · 技术社区  · 14 年前

    所以,我是个perl新手。虽然我有更复杂的事情要做,我突然遇到了一个路障,无法找出wtf是错误的代码。我已经大大简化了它,它只是一个非常小的代码片段。

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

    流程.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};
    

    我跑了流程.pl我得到以下输出

    通过类访问:

    我也得到了警告

    在中使用未初始化的值 连接(.)或字符串测试.pl 第12行(#1) (W uninitialized)一个未定义的值被当作已经被使用 若要抑制此警告,请为变量指定一个定义的值。

    3 回复  |  直到 14 年前
        1
  •  6
  •   Philip Potter    14 年前

    对象实例作为第一个参数传递给方法。通常的做法是将其存储在一个名为 $self ,但perl并没有为您设置此功能,您必须自己设置:

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

    strict warnings test.pl 也就是说 是使用未定义的值静默创建的,而不是因为使用未声明的变量而引发编译错误。

    此外,我建议你 package Test 一个叫做 Test.pm 1; use Test; 而不是 do "test.pl"

        2
  •  3
  •   daotoad    14 年前

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

    • 将对象定义放在以结尾的文件中 .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";  
    }
    

    流程.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.
    

    如果你正在做大量的面向对象编程,请考虑学习使用 Moose . Moose是一个强大的、超现代的Perl对象系统,它增加了强大的功能并减少了样板代码。

    如果您想学习“经典的”perloop,perldoc中的教程( perlboot perltoot perlobj , perlbot perltooc )很不错。如果你想深入研究, Damian Conway's Object Oriented Perl 是一本很棒的书。

        3
  •  0
  •   Toto    14 年前

    在子日志中:

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