perl - 为什么 version->parse 在没有预先打印的情况下无法工作?

标签 perl version

我不得不承认,这个让我感到困惑。

考虑这个代码:

use version;
use Data::Dumper;
my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)};
print STDERR qq{$codeLevel\n};
my $vrmf;
if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) { 
    print STDERR "$1\n";
    $vrmf = version->parse($1);
}

print STDERR Dumper($vrmf);

正如预期的那样,输出是:
6.1.0.7 (build 25.3.1103030000)
6.1.0.7
$VAR1 = bless( {
                 'original' => '6.1.0.7',
                 'qv' => 1,
                 'version' => [
                                6,
                                1,
                                0,
                                7
                              ]
               }, 'version' );

但是,删除第二个打印:
use version;
use Data::Dumper;
my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)};
print STDERR qq{$codeLevel\n};
my $vrmf;
if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) {
    $vrmf = version->parse($1);
}
print STDERR Dumper($vrmf);

输出变为:
6.1.0.7 (build 25.3.1103030000)
$VAR1 = bless( {
                 'original' => '0',
                 'version' => [
                                0
                              ]
               }, 'version' );

我找不到任何说明 print 会影响传递给它的变量,或者它会影响正则表达式匹配变量的文档。

有人可以向我解释这里发生了什么吗?

最佳答案

Perl 中的标量值可以同时是数字和字符串。 SV 对象(SV = 标量值)具有用于整数、浮点数和字符串值的插槽以及标识这些值中哪些值在任何时间点都有效的标志。当您使用一个值作为字符串时,perl 会计算该字符串值并设置一个标识它为有效的标志。 (其他操作,例如加 1 会使字符串值无效。)当您打印某些内容时,您(不出所料)将其用作字符串。您可以使用 Devel::Peek 看到这一点。

use Devel::Peek;

my $s = '6.1.0.7 (build 25.3.1103030000)';
if ($s =~ /^\s*([0-9.]*) \(build.*\)/) { 
    Dump($1);
    printf STDERR "\$1 = $1\n";
    Dump($1);
}

结果是
SV = PVMG(0x1434ca4) at 0x144d83c
  REFCNT = 1
  FLAGS = (GMG,SMG)
  IV = 0
  NV = 0
  PV = 0
  MAGIC = 0x146c324
    MG_VIRTUAL = &PL_vtbl_sv
    MG_TYPE = PERL_MAGIC_sv(\0)
    MG_OBJ = 0x144d82c
    MG_LEN = 1
    MG_PTR = 0x14631c4 "1"
$1 = 6.1.0.7
SV = PVMG(0x1434ca4) at 0x144d83c
  REFCNT = 1
  FLAGS = (GMG,SMG,pPOK)
  IV = 0
  NV = 0
  PV = 0x1487a1c "6.1.0.7"\0
  CUR = 7
  LEN = 8
  MAGIC = 0x146c324
    MG_VIRTUAL = &PL_vtbl_sv
    MG_TYPE = PERL_MAGIC_sv(\0)
    MG_OBJ = 0x144d82c
    MG_LEN = 1
    MG_PTR = 0x14631c4 "1"

请注意,在第二个转储输出中,PV 插槽(字符串值)已填充,并且 pPOK 标志已添加到 FLAGS 下。

所以,是的,print 有某种副作用,尽管在正常情况下你永远不会注意到。 version->parse() 似乎需要一个字符串参数,但不会触发字符串语义。鉴于 version 更喜欢使用 XS 实现,它可能是那里的一个错误,而不是 perl。请注意,制作捕获数据的副本会导致问题消失:
use Data::Dump qw'pp';

my $s = '6.1.0.7 (build 25.3.1103030000)';
if ($s =~ /^\s*([0-9.]*) \(build.*\)/) { 
    my $x = $1;
    pp(version->parse($x));
}

结果:
bless({ original => "6.1.0.7", qv => 1, version => [6, 1, 0, 7] }, "version")

关于perl - 为什么 version->parse 在没有预先打印的情况下无法工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6755120/

相关文章:

perl - 谁能解释为什么 foreach 有效但 map 无效

perl - 如何将 Perl sub 的返回值转换为 arrayref?

json - WWW::Wunderground::API 无法保佑 无引用值(value)

perl - 为什么 CGI::Session new 和加载失败(无法解冻())?

java - 我的 Ubuntu 安装上的 Java 版本是 "1.8.0_191"?

mysql - 使用DBI启用SQL跟踪时,如何防止语句多次输出?

gradle - 如何使用 Gradle 在依赖标记之外的变量上设置版本?

java - Ant 任务: read and user manifest implementation version

javascript - 使用 Angular.js 版本 1.2.18 进行嵌套过滤

r - 用于包安装的 false R 版本