edu*_*inn 2 perl pass-by-reference
我正在维护旧的Perl代码,需要在所有模块中启用严格的pragma.我在传递文件句柄作为模块和subs之间的引用时遇到问题.我们有一个公共模块负责打开日志文件,该文件作为typeglob引用传递.在其他模块中,run函数首先从公共模块调用open_log(),然后将此文件句柄传递给其他subs.
在这里,我写了一个简单的测试来模拟这种情况.
#!/usr/bin/perl -w
use strict;
$::STATUS_OK = 0;
$::STATUS_NOT_OK = 1;
sub print_header {
our $file_handle = @_;
print { $$file_handle } "#### HEADER ####"; # reference passing fails
}
sub print_text {
my ($file_handle, $text)= @_;
print_header(\$file_handle);
print { $$file_handle } $text;
}
sub open_file_handle {
my ($file_handle, $path, $name) = @_;
my $filename = $path."\\".$name;
unless ( open ($$file_handle, ">".$filename)) {
print STDERR "Failed to open file_handle $filename for writing.\n";
return $::STATUS_NOT_OK;
}
print STDERR "File $filename was opened for writing successfully.\n";
return $::STATUS_OK;
}
my $gpath = "C:\\Temp";
my $gname = "mylogfile.log";
my $gfile_handle;
if (open_file_handle(\$gfile_handle, $gpath, $gname) == $::STATUS_OK) {
my $text = "BIG SUCCESS!!!\n";
print_text(\$gfile_handle, $text);
print STDERR $text;
} else {
print STDERR "EPIC FAIL!!!!!!!!\n";
}
Run Code Online (Sandbox Code Playgroud)
Main函数首先调用open_file_handle并传递对该print_text函数的文件句柄引用.如果我注释掉这一行:
print_header(\$file_handle);
Run Code Online (Sandbox Code Playgroud)
一切正常,但我需要将文件句柄引用传递给函数中的其他print_text函数,这不起作用.
我是一名Java开发人员,Perl的参考处理对我来说并不熟悉.我不想更改open_log()sub来返回文件句柄(现在它只返回状态),因为我有很多模块和数百个代码行可以在所有地方进行此更改.
如何修复我的代码才能使其正常工作?
Perl中有两种类型的文件句柄.词法和全局裸字文件句柄:
open my $fh, '>', '/path/to/file' or die $!;
open FILEHANDLE, '>', '/path/to/file' or die $!;
Run Code Online (Sandbox Code Playgroud)
你正在处理第一个,这很好.第二个是全球性的,不应该使用.
您拥有的文件句柄是词法,它们存储在标量变量中.它被称为标量,因为它有一个美元符号$.这些可以作为参数传递给subs.
foo($fh);
Run Code Online (Sandbox Code Playgroud)
它们也可以被引用.在这种情况下,您将获得标量参考.
my $ref = \$fh;
Run Code Online (Sandbox Code Playgroud)
通常你引用的东西,如果你把它交给一个函数,所以Perl不会复制数据.可以想象像C中的指针一样的引用.它只是数据(结构)的内存位置.这段数据本身仍然存在.
现在,在您的代码中,您可以引用这些标量.你可以说,因为它在print声明中被解除引用$$fh.
sub print_text {
my ($file_handle, $text)= @_;
print_header(\$file_handle);
print { $$file_handle } $text;
}
Run Code Online (Sandbox Code Playgroud)
所以$file_handle你得到一个参数(这就是它的= @_作用)实际上是一个参考.将函数传递给函数时,不需要再次引用它.
我想你print_header自己写的:
sub print_header {
our $file_handle = @_;
print { $$file_handle } "#### HEADER ####"; # reference passing fails
}
Run Code Online (Sandbox Code Playgroud)
这里有一些事情: - our是全局的.不要使用它.请my改用.- 在参数赋值周围加上括号:my ($fh) = @_
- 由于您将对引用的引用传递给标量,因此需要取消引用两次:${ ${ $file_handle } }
当然,双击是很奇怪的.摆脱它传递变量$file_hanlde来print_header代替refence它的:
sub print_text {
my ($file_handle, $text)= @_;
print_header($file_handle); # <-- NO BACKSLASH HERE
print { $$file_handle } $text;
}
Run Code Online (Sandbox Code Playgroud)
这就是让它发挥作用所需的一切.
一般来说,我会在$file_handle这里删除所有对变量的引用.你不需要它们.词法文件句柄已经是对IO :: Handle对象的引用,但是现在不关心它,它并不重要.只记得:
$前面\和${}之类的东西有关详细信息,请参阅perlref和perlreftut.