【发布时间】:2022-02-07 04:59:31
【问题描述】:
我一直在尝试制作一个相对较大的 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)的值从内存中删除!如果我简单地调用该函数,则不会发生任何令人讨厌的事情。所以,我用for 语句(表格2)替换了given/when 用法,我的问题是为什么问题仍然存在?!真正避免该问题的唯一形式是if/elsifs 的简单链(形式 3),这清楚地表明问题出在形式 1 和 2 以及 perl 解释器不一致且漏洞百出:它甚至不会对表格 2 产生“实验性”警告。
这是表格1(原件):
print "ailtype is $ailtype \n"; # 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.\n"; }
}
print "ailtype is $ailtype \n"; # prints "ailtype is ". $ailtype got destroyed!
prints 用于调试。我可以将它们放在when 块中,并确认$ailtype 在&parse_spectrast 函数调用后被销毁。但是,该功能根本不会读取或触摸$ailtype! (有趣的是,如果我进入函数内部并打印$ailtype 的值以准确找到它被搞砸的地方,我发现它发生在解析输入文件行的while 循环中。以某种方式打印$ailtype返回该文件的行!)
该程序由几个带有许多 given/when 语句的大型 perl 文件组成,并且手动重写所有这些语句会很乏味。我必须确保替代形式有效。所以我尝试了表格2(建议here):
print "ailtype is $ailtype \n"; # 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.\n"; }
}
print "ailtype is $ailtype \n"; # prints "ailtype is ". $ailtype still gets destroyed!
这种形式还是出现问题,我真的不明白为什么?!解释器不再在此处警告实验性given/when(尽管它们仍在代码的其他地方使用。我确保它们没有出现在有问题的块之前并且没有帮助)。
不管你是否感到惊讶,if/elsifs 链(表格 3)工作正常:
print "ailtype is $ailtype \n"; # 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.\n";
}
print "ailtype is $ailtype \n"; # prints "ailtype is 8". It was never changed.
但我认为 Perl 的强大功能可以让我们不必编写所有这些代码。如果我确定我有一个可靠的口译员,我会愿意这样做。将版本更改为 v5.16.3(两个平台上安装的最新版本)只会产生关于声明的新错误,“不允许使用裸字 STDOUT”等。单独与这个错误斗争了 10 个小时,我非常怀疑。
【问题讨论】:
-
你调用的潜艇是做什么的?你怎么能问这样的问题而不包括这些信息?您应该包含完整且最少的代码,可以运行以演示您的问题。
-
@TLP 他们做了很多事情,而且太大了,不能在这里发帖。但正如我所说,他们根本不阅读或更改
$ailtype。一次也没提过。简单地调用问题点函数或使用if可以避免问题的事实应该清楚地表明,函数的作用并不重要。 -
@TLP 我会尝试制作一个最小的独立代码来重现问题。
-
“当程序调用相同的先前版本v5.10.1时,解释器行为在两种环境中应该是相同的”。不清楚你的意思。如果您认为
use v5.10.1将使它使用这个版本的Perl - 它不会。它只确保您运行的是至少 5.10.1,并且它会开启5.10.1 引入的一些功能。 -
我忍不住要这么说:我们需要说多少次
given-when和smartmatch(尤其是!)有严重的问题,他们将被改变,也许无法识别(或更糟)?繁琐与否,只需替换那些代码部分,并小心使用尽可能简单和最清晰的代码(这些重载功能的问题的一部分,它们悄悄地引入了各种假设)。对不起。它发生了。
标签: perl switch-statement match given