我有一些代码,我已经设法缩小到以下最小代码示例.
首先,我有一个plugh.pm负责读取配置文件的模块.基本上可以用以下内容替换它,它设置了一个配置项:
use strict;
use warnings;
sub cfgRead () { $main::cfg{"abc"} = "/usr"; }
1;
Run Code Online (Sandbox Code Playgroud)
然后我有一个主程序,它使用该模块如下,只需调用函数来设置配置项,然后在子例程中使用其中一个项:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.005;
require File::Basename;
import File::Basename "dirname";
push (@INC, dirname ($0));
require plugh;
my (%cfg);
sub subOne () {
my $list = `ls -1 $main::cfg{"abc"}`;
my @list = split (/\s+/, $list);
my $fspec;
foreach $fspec (@list) {
print $fspec . "\n";
}
}
sub mainLine () {
cfgRead();
subOne();
}
mainLine();
Run Code Online (Sandbox Code Playgroud)
现在,当我运行它时,我得到以下输出,第一行是标准错误,其余是标准输出:
Name "main::cfg" used only once: possible typo at /home/xyzzy/bin/xyzzy line 15.
bin
games
include
lib
lib64
local
sbin
share
src
Run Code Online (Sandbox Code Playgroud)
它抱怨的是ls -1子进程创建.我的问题很简单:那又怎样?是的,我只使用过一次,但为什么这也是一个问题?
如果我从来没有使用它,那很好,但我不明白为什么Perl警告我只使用它一次.
我从关联数组中获取变量,然后使用它来获取目录列表.是否存在某种奇怪的Perl指南,规定变量必须至少使用两次?七次?四十二?我很难过.
TLP*_*TLP 12
我认为您的原始问题已经得到解答,所以我会传达我的建议.如果你能避免它,就不要使用全局变量.您正在使用子程序作为代码集群,而不是传递任何参数,这就是您的问题所在.
模块:
sub cfgRead {
my %cfg;
$cfg{"abc"} = "/usr";
...
return \%cfg;
}
Run Code Online (Sandbox Code Playgroud)
主要:
sub subOne {
my $cfg = shift;
my $list = `ls -1 $cfg->{"abc"}`;
....
}
my $cfg = cfgRead();
subOne($cfg);
Run Code Online (Sandbox Code Playgroud)
这里有一些奇怪的事情.
第一:当您use strict处于活动状态时,如果您使用变量而未声明变量,或者通过完全限定名称引用变量,则会收到警告.
你实际做的是%cfg用my()in 声明一个local xyzzy.pl,然后引用一个不同的 package-global变量%main::cfg(使用它的完全限定名隐式声明).
要使引用链接与%cfg您声明的引用链接相同,您应该声明它our()以使其成为package-global.然后你可以像$main::cfg{}在两个地方(或者只是$cfg{}从xyzzy.pl)一样引用它,或者你也可以our()在它中声明它plugh.pm(这样你就可以在两个地方都使用裸%cfg).
奇怪的是,你确实有两个对该变量的引用,所以你不应该得到警告.我认为这里发生的事情是两个单独文件中的隐式声明被假定为单独的变量.
xyzzy.pl:
require plugh;
our (%cfg);
sub subOne () {
my $list = `ls -1 $cfg{"abc"}`;
...
}
Run Code Online (Sandbox Code Playgroud)
plugh.pm:
our(%cfg);
sub cfgRead () { $cfg{"abc"} = "/usr"; }
Run Code Online (Sandbox Code Playgroud)
这只是一个有用的评论,因为将数据存储在某些内容中却非常不寻常,但从未再次查看过.让我们看一个更有用的例子:
use warnings;
$something = 1;
$something = $something + 1;
Run Code Online (Sandbox Code Playgroud)
当然,这正如您所期望的那样有效.但考虑一个错误:
use warnings;
$something = 1;
$something = $somehting + 1;
Run Code Online (Sandbox Code Playgroud)
如果你没有仔细观察,你就不会注意到拼写错误,也可能无法弄清楚为什么最终值是错误的(因为$somehting它实际上是0).
在这种情况下警告:
Name "main::somehting" used only once: possible typo at tmp.pl line 3.
Run Code Online (Sandbox Code Playgroud)
更有用.它显示了一个可能的拼写错误.
(use strict;当然在这里会更好)