带有给定时间和用于匹配的隐藏错误。Perl真的是跨平台的吗? [英] Hidden bugs with given-when and for-match. Is Perl truly cross-platform?
问题描述
我一直在尝试制作一个相对较大的Perl程序,该程序多年来在CentOS上一直工作得很好,可以在Ubuntu上工作,但这已经成为一个巨大的噩梦。CentOS使用为x86_64-Linux-THREAD-MULTI构建的Perl,而Ubuntu使用x86_64-LINUX-GNU-THREAD-MULTI构建。AFAIK,当程序调用相同的先前版本v5.10.1
时,两个环境中的解释器行为应该相同。然而,我得到了非常不同的行为,包括关于given
/when
和smartmatch
处于实验阶段的警告,最重要的是,一组难以跟踪和解决的令人讨厌的错误。当下面所示的given
语句(表单1)匹配并调用函数时,会出现一个特别的问题。然后,开关变量(称为$ailtype
)的值(称为$ailtype
)将突然从内存中删除!如果我简单地调用该函数,不会发生任何令人讨厌的事情。因此,我将given
/when
用法替换为for
语句(Form 2),我的问题是为什么问题仍然出现?!真正避免该问题的唯一表单是一个简单的if
/elsif
链(表单3),这清楚地表明问题出在表单1和表单2上,而Perl解释器不一致且充满错误:它甚至不会为表单2生成实验性警告。
这是表格1(原件):
print "ailtype is $ailtype
"; # prints "ailtype is 8"
given ($ailtype) {
when (4) { &parse_mascot}
when (5) { &parse_sequest}
when (8) { &parse_spectrast($ms2_results, $rttemp)}
when (9) { &parse_cnstab($ms2_results, $rttemp)}
default { STDOUT->autoflush(1) and die "ailtype=|$ailtype| unknown.
"; }
}
print "ailtype is $ailtype
"; # prints "ailtype is ". $ailtype got destroyed!
print
用于调试。我可以将它们放在when
挡路中,并确认$ailtype
在&parse_spectrast
函数调用后被销毁。但是,该函数根本不读取或触摸$ailtype
!(有趣的是,如果我进入函数内部并打印$ailtype
的值以找出错误的确切位置,我会看到它发生在解析输入文件行的while
循环中。打印$ailtype
以某种方式返回该文件的行!)该程序由几个带有多个given
/when
语句的大型Perl文件组成,手动重写所有这些语句将非常繁琐。我必须确保另一种形式有效。所以我尝试了Form 2(建议here):
print "ailtype is $ailtype
"; # prints "ailtype is 8"
for ($ailtype) {
/4/ and do { &parse_mascot; last};
/5/ and do { &parse_sequest; last};
/8/ and do { &parse_spectrast($ms2_results, $rttemp); last};
/9/ and do { &parse_cnstab($ms2_results, $rttemp); last};
do { STDOUT->autoflush(1) and die "ailtype=|$ailtype| unknown.
"; }
}
print "ailtype is $ailtype
"; # prints "ailtype is ". $ailtype still gets destroyed!
问题仍然出现在这个表单中,我真的不明白为什么?!解释器不再警告这里的试验性given
/when
(尽管它们仍然在代码的其他地方使用。我确保它们不会在有问题的挡路出现之前发生,这没有任何帮助)。
不管是否令人惊讶,if
/elsif
s(Form 3)链工作正常:
print "ailtype is $ailtype
"; # prints "ailtype is 8"
if (4 == $ailtype) {
&parse_mascot;
}
elsif (5 == $ailtype) {
&parse_sequest;
}
elsif (8 == $ailtype) {
&parse_spectrast($ms2_results, $rttemp);
}
elsif (9 == $ailtype) {
&parse_cnstab($ms2_results, $rttemp);
}
else {
STDOUT->autoflush(1) and die "ailtype=|$ailtype| unknown.
";
}
print "ailtype is $ailtype
"; # prints "ailtype is 8". It was never changed.
但我认为Perl的强大功能使我们不必编写所有这些代码。如果我确信我有一个可靠的口译员,我会愿意这样做的。将版本更改为v5.16.3(两个平台上安装的最新版本)只会产生有关声明、不允许使用无字STDOUT等的新错误。单独与此错误斗争了10个小时后,我对此深表怀疑。
推荐答案
for
循环中每个值的别名。如果调用的函数更改了$_
的值,则原始变量也会更改。While循环中使用的菱形运算符更改全局$_
,并在eof
上变为undef
。
#!/usr/bin/perl
use warnings;
use strict;
sub f {
while (<DATA>) {
warn "read: $_";
}
}
my $x = 8;
print "Before:<<$x>>
";
for ($x) {
&f();
}
print "After:<<$x>>
";
__DATA__
A
B
解决方案:
在while (<>) {
之前插入以下行:
local $_;
这将在离开local
语句的作用域时还原$_
的原始值。
这篇关于带有给定时间和用于匹配的隐藏错误。Perl真的是跨平台的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!