Update3:
如果你喜欢这个帖子,请不要向我投票,而是通过下面的DVK赞助天才答案。
我有以下子程序:
use warnings;
#Input
my @pairs = (
"fred bill",
"hello bye",
"hello fred",
"foo bar",
"fred foo");
#calling the subroutine
my @ccomp = connected_component(@pairs);
use Data::Dumper;
print Dumper \@ccomp;
sub connected_component {
my @arr = @_;
my %links;
foreach my $arrm ( @arr ) {
my ($x,$y) = split(/\s+/,$arrm);;
$links{$x}{$y} = $links{$y}{$x} = 1;
}
my %marked; # nodes we have already visited
my @stack;
my @all_ccomp;
for my $node (sort keys %links) {
next if exists $marked{$node};
@stack = ();
connected($node);
print "@stack\n";
push @all_ccomp, [@stack];
}
sub connected {
no warnings 'recursion';
my $node = shift;
return if exists $marked{$node}; # Line 43
$marked{$node} = 1;
push @stack, $node; # Line 45
my $children = $links{$node}; # Line 46
connected($_) for keys %$children;
}
return @all_ccomp;
}
但为什么它会传达这样的信息:
Variable "%marked" will not stay shared at mycode.pl line 43.
Variable "@stack" will not stay shared at mycode.pl line 45.
Variable "%links" will not stay shared at mycode.pl line 46.
有害吗?错误?如何修复我的代码,以便它摆脱那条消息?
Update1:我使用确实错误消息更新运行的代码
Update2:我尝试使用sub修改为DVK建议。它工作了!
use warnings;
#Input
my @pairs = (
"fred bill",
"hello bye",
"hello fred",
"foo bar",
"fred foo");
#calling the subroutine
my @ccomp = connected_component(@pairs);
use Data::Dumper;
print Dumper \@ccomp;
sub connected_component {
my @arr = @_;
my %links;
foreach my $arrm ( @arr ) {
my ($x,$y) = split(/\s+/,$arrm);;
$links{$x}{$y} = $links{$y}{$x} = 1;
}
my %marked; # nodes we have already visited
my @stack;
my @all_ccomp;
my $connected_sub;
$connected_sub = sub {
no warnings 'recursion';
my $node = shift;
return if exists $marked{$node};
$marked{$node} = 1;
push @stack, $node;
my $children = $links{$node};
&$connected_sub($_) for keys %$children;
};
for my $node (sort keys %links) { # Line 43
next if exists $marked{$node};
@stack = ();
&$connected_sub($node);
#print "@stack\n";
push @all_ccomp, [@stack]; # Line 49
}
return @all_ccomp;
}
答案 0 :(得分:53)
根据perldoc's perldiag对于该错误,您的问题是内部子引用了外部子中定义的词法变量(标记为%)。
修复程序位于第三段(使用匿名子):
(警告;闭包)一个内部(嵌套)命名 子程序引用词法 在外部命名中定义的变量 子程序。
调用内部子程序时 它会看到外部的价值 子程序的变量和以前一样 并在第一次调用期间 外子程序;在这种情况下,之后 第一次调用外部子程序 完整,内在和外在 子程序将不再共享一个 变量的公共值。在 换句话说,变量将不会 更长时间的分享。
这个问题通常可以解决 使内部子程序匿名, 使用sub {}语法。内心的时候 匿名潜水员参考 外部子程序中的变量是 创建,它们是自动的 反弹到这样的当前价值 变量
使用匿名子修正代码:
# ....
my $connected_sub;
$connected_sub = sub {
no warnings 'recursion';
my $node = shift;
return if exists $marked{$node}; # Line 280
$marked{$node} = 1;
push @stack, $node; # Line 282
my $children = $links{$node}; # Line 283
&$connected_sub($_) for keys %$children;
};
for my $node (sort keys %links) {
next if exists $marked{$node};
@stack = ();
&$connected_sub($node);
#print "@stack\n";
push @all_ccomp, [@stack];
}
# ....
答案 1 :(得分:6)
从perl获取诊断消息时,通常最好查看perldiag
以了解它的含义。该联机帮助页也恰好涵盖了您收到的警告。
基本上,命名子例程不会按照您期望的方式嵌套。解决方案包括使用匿名内部子例程,而不是嵌套命名子例程,只是明确地在它们之间传递状态,或者使用CPAN中的mysubs
之类的东西。
答案 2 :(得分:6)
另一种(可能更简单)的出路是将变量声明为“我们的”而不是“我的”
所以,
our %marked;
而不是
my %marked;
等
答案 3 :(得分:0)
如果您不小心在脚本的主线程中重新声明了共享变量,也会发生此错误,
`
use vars qw(%types %colors);
my %types = (...); # bad
%colors = (...); # good
`