带有给定时间和用于匹配的隐藏错误。Perl真的是跨平台的吗? [英] Hidden bugs with given-when and for-match. Is Perl truly cross-platform?

查看:44
本文介绍了带有给定时间和用于匹配的隐藏错误。Perl真的是跨平台的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试制作一个相对较大的Perl程序,该程序多年来在CentOS上一直工作得很好,可以在Ubuntu上工作,但这已经成为一个巨大的噩梦。CentOS使用为x86_64-Linux-THREAD-MULTI构建的Perl,而Ubuntu使用x86_64-LINUX-GNU-THREAD-MULTI构建。AFAIK,当程序调用相同的先前版本v5.10.1时,两个环境中的解释器行为应该相同。然而,我得到了非常不同的行为,包括关于given/whensmartmatch处于实验阶段的警告,最重要的是,一组难以跟踪和解决的令人讨厌的错误。当下面所示的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/elsifs(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆