0

我需要在几个 perl 模块中使用相同的文件句柄。这是我的示例 a.pl

#!/usr/bin/perl -w

our $OUT_FILE_HANDLE;

require b;

open($OUT_FILE_HANDLE, ">./a.log");
print $OUT_FILE_HANDLE "text1\n";

b::f($OUT_FILE_HANDLE); // this works

下午

package b;

sub f($) {
  my $a = shift;
  print $a "text2\n";  // get error here
}

f($main::OUT_FILE_HANDLE);
1;

我收到错误“不能使用未定义的值作为符号引用”

如果我直接在 b.pm 中使用句柄(不将其作为参数传递给函数)它工作正常

下午

package b;

sub f() {
  print $main::OUT_FILE_HANDLE "text2\n";  // this works
}

f();
1;
4

4 回答 4

9

由于执行顺序,您的示例失败:所有 b.pm 在您执行时执行require b;。因此,您试图在打开文件句柄之前使用它。

作为一般原则,模块应该只通过可以调用的函数来做事。当需要模块时,只有初始化的东西才应该运行。

在这种情况下,最好的设计是使用词法文件句柄并将其传递给任何需要它的函数。不要使用全局。

open(my $OUT_FILE_HANDLE, '>', './a.log') or die "Ouch: $!";
print $OUT_FILE_HANDLE "text1\n";

b::f($OUT_FILE_HANDLE);

使用全局变量与模块进行通信很少是一个好主意。有时,模块向调用代码公开全局变量可能很有用,但反过来也不是一个好的设计。模块不应依赖于特定包中存在的特定变量才能工作。

最后,您几乎不应该在 Perl 中使用子例程原型。只需省略原型,除非您完全了解 Perl 原型并且有充分的理由使用它们:

sub f {
于 2013-03-28T13:03:44.557 回答
3

你的代码有很多问题。

  • 始终 位于程序的顶部或use strict语句之后use warningspackage

  • 用于CamelCase包名称和snake_case本地标识符。熟悉 Perl 的人会感谢你

  • 对所有标识符使用描述性的内容。特别是有一个名为B(Perl Compiler Backend)的核心包,所以这不会做

  • 永远不要main期望辅助模块从包中访问数据。流动应严格自下而上

  • 永远不要为你的子程序使用原型。Perl 在这方面与其他语言不同,原型做了一些非常特殊的事情。如果你不知道这些东西是什么,那么你当然不应该使用原型

  • require除非你知道它的作用,否则不要使用。你几乎肯定想要use

  • 使用 的三参数形式open经常检查是否成功。如果open失败,那么您应该die使用一个字符串,包括$!说明失败的原因

您的代码未按预期工作的主要原因是require(and ) 语句将在包含辅助模块use执行辅助模块中的任何可执行语句。通常,此类模块将仅包含用于调用代码的定义声明,如果包含任何可执行代码,则必须非常小心,因为如您所见,它可能会导致依赖关系不可用的问题。

这是您的代码的工作版本

主文件

use strict;
use warnings;

use BB;

open my $fh, '>', 'a.log' or die $!;
print $fh "text1\n";

BB::f($fh);

下午

package BB;

use strict;
use warnings;

sub f {
  my ($a) = @_;
  print $a "text2\n";
}

1;

输出(到a.log

text1
text2
于 2013-03-28T14:42:02.190 回答
1

B 对模块来说是个坏名字,因为它是Perl 核心模块。用 BB 重命名它(例如)。此外,Perl 注释使用“#”,也不是“//”。这是我修改后的代码(效果很好):

主文件

use BB;

our $OUT_FILE_HANDLE;
open($OUT_FILE_HANDLE, ">", "./a.log") or die $!;
print $OUT_FILE_HANDLE "text1\n";
BB::f($OUT_FILE_HANDLE);

下午

package BB;

sub f {
  my $a = shift;
  print $a "text2\n";  
}
1;
于 2013-03-28T13:25:05.873 回答
-1

也许移动“我们的 $OUT_FILE_HANDLE;” 在您的 b.pm 包中。

于 2013-03-28T13:04:14.730 回答