在子例程中通过引用操作Perl对象

时间:2015-10-20 12:21:41

标签: perl object reference perl-module subroutine

我有一个Perl程序并打包WorkerLog

Worker几乎完成所有计算,我想通过引用Worker子例程以及一些其他参数(标量和数组)来传递一个对象。我见过thisthis等示例。

他们通过将@_置于子中,然后操纵对象来处理此问题。我还找到了一种使用索引来操纵它们的方法,比如@{$_[i]}。问题是,当我尝试这样的代码时,我收到一个错误: Can't call method "write" on unblessed reference at ...

以下代码段。

主:

use strict;
use warnings;
use Log;
use Worker;

my $log = Log->new();
my $worker = Worker->new();
my $scalar = "SomeURLhere";
my @array = ('red','blue','white');

# I do some stuff with $log object
#...
# Now I want to pass data to the Worker
$worker->subFromWorker($scalar, \$log, \@array);

工人:

use strict;
use warnings;
package Worker;

sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub subFromWorker{
    my ($self) = shift;
    my $scalar = $_[0];
    #my ($log) = $_[1];
    my @array = @{$_[2]};

    foreach my $item (@array){
        print $item;
    }

    $_[1]->write("The items from url $scalar are printed.");

    #Same thing happens if I use $log here
}

在C#中,这是以不同的方式处理的 - 您可以通过值或引用将参数发送到方法,然后在专门的方法中执行您想要的操作(预编写方法以通过引用处理参数或值)。我认为在Perl中使用\parameter发送将发送引用。

3 个答案:

答案 0 :(得分:6)

对象是引用。参考是标量值。

如果要将数组或散列传递给子例程,那么通常需要传递对它们的引用 - 因为Perl参数传递对标量值的效果要好得多。

$log已经是对象的引用。因此,您不需要参考它。您最终传递了对引用的引用。因此,当您将该参数复制到子例程中的$log时,您将获得额外的,不必要的引用级别。

修复方法是将$log标量传递给子例程。

$worker->subFromWorker($scalar, $log, \@array); # $log, not \$log

其他一切都会正常工作。

答案 1 :(得分:3)

您已阅读有关阻止您的计划工作的问题,但您还应了解其他一些事项

  • Perl词法标识符和子例程/方法名称由字母数字和下划线组成。大写字母保留用于全局标识符,例如WorkerLog等包名。

  • userequire的文件包应以语句1;结尾,以便在导入时返回 true 值,否则你的程序可能无法编译。

  • 如果您正在编写的子程序恰好是方法,那么最好通过移开$self参数并复制其余部分来启动它。 :

    my $self = shift;
    my ($p1, $p2, $p3) = @_;
    

    很少直接使用@_的元素,除非您急需最低速度奖金

  • 通常最好直接使用数组引用而不是复制数组,特别是如果它可能很大。

以下是我对程序和相关模块进行编码的方法:

program.pl

use strict;
use warnings;

use Worker;
use Log;

my $log    = Log->new;
my $worker = Worker->new;

my $scalar = 'SomeURLhere';
my @array  = qw/ red blue white /;

$worker->worker_method($scalar, $log, \@array);

Worker.pm

use strict;
use warnings;

package Worker;

sub new {
    my $class = shift;
    my $self  = {};
    bless $self, $class;
    return $self;
}

sub worker_method {
    my $self   = shift;
    my ($scalar, $log, $array) = @_;

    foreach my $item (@$array) {
        print $item, "\n";
    }

    $log->write("The items from URL $scalar are printed.");
}

1;

Log.pm

use strict;
use warnings;

package Log;

sub new {
    my $class = shift;
    bless {}, $class;
}

sub write {
    my $self   = shift;
    my ($text) = @_;

    print "Logging: $text\n"
}

1;

输出

red
blue
white
Logging: The items from URL SomeURLhere are printed.

答案 2 :(得分:0)

更常见的模式是使用List赋值将@_解压缩为多个变量:

sub subFromWorker {
   my ($self, $scalar, $log_ref, $array) = @_;
   ...
}

参考您的具体问题:

my $log = Log->new();

$log 对您的对象的引用,使用\$log创建对该引用的引用,这可能不是您想要的。您可以通过以下两种方式处理:

  1. 仅通过$log
    • $worker->subFromWorker($scalar, $log, \@array);
  2. 在调用函数之前,在$log中取消引用subFromWorker
    • $$log_ref->write('...');