我有一个Perl程序和Worker
和Log
包。
Worker完成了几乎所有的计算,我想通过引用传递一个对象给Worker子例程,以及一些其他参数(标量和数组)。我看到过这样和这样的例子。
他们通过将@_
放在subs中,然后操作对象来处理这个问题。我还发现了一种通过使用索引来操纵它们的方法,比如@{$_[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
将发送引用。
对象是引用。引用是标量值。
如果你想把数组或哈希值传递给子例程,那么你通常想要传递对它们的引用——因为Perl参数传递对标量值的效果要好得多。
但是$log
已经是你的对象的引用了。因此你不需要引用它。最终将一个引用传递给另一个引用。因此,当您将该参数复制到子程序中的$log
中时,您就有了额外的,不必要的引用级别。
解决方法是将$log
标量传递到子例程。
$worker->subFromWorker($scalar, $log, @array); # $log, not $log
您已经了解了妨碍程序工作的问题,但是还有一些其他的事情您应该注意
-
Perl词法标识符和子例程/方法名由字母数字和下划线组成。全局标识符保留大写字母,如
Worker
和Log
等包名。 -
您的
use
或require
包应该以语句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: $textn"
}
1;
输出red
blue
white
Logging: The items from URL SomeURLhere are printed.
更常见的模式是使用List赋值将@_
一次解压缩为多个变量:
sub subFromWorker {
my ($self, $scalar, $log_ref, $array) = @_;
...
}
针对您的具体问题:
my $log = Log->new();
$log
是已经一个引用到你的对象,使用$log
创建一个引用到那个引用,可能不是你想要的。您可以通过以下两种方式处理:
- 仅通过
$log
:-
$worker->subFromWorker($scalar, $log, @array);
-
- 在
subFromWorker
上调用函数之前取消对$log
的引用:-
$$log_ref->write('...');
-