如何将文件句柄作为参数传递给perl中的模块和subs

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来返回文件句柄(现在它只返回状态),因为我有很多模块和数百个代码行可以在所有地方进行此更改.

如何修复我的代码才能使其正常工作?

sim*_*que 8

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_hanldeprint_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对象引用,但是现在不关心它,它并不重要.只记得:

  • 使用有一个文件句柄$前面
  • 通过他们没有引用,你不必担心\${}之类的东西

有关详细信息,请参阅perlrefperlreftut.