为什么版本->解析在没有前面打印的情况下无法工作?
我不得不承认,这个让我着迷。
考虑这段代码:
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
可以影响传递给它的变量的文档,或者它影响正则表达式匹配变量。
有人可以向我解释一下这里发生了什么吗?
I have to admit, this one has me foxed.
Consider this code:
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);
The output, as expected, is:
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' );
However, remove the second print:
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);
The output becomes:
6.1.0.7 (build 25.3.1103030000)
$VAR1 = bless( {
'original' => '0',
'version' => [
0
]
}, 'version' );
I can't find any documentation that says that print
can affect variables passed to it, or that it affects the regex matching variables.
Can someone explain to me what is happening here, please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Perl 中的标量值可以同时是数字和字符串。。 SV 对象(SV = 标量值)具有用于整数、浮点和字符串值的槽以及标识这些值中哪些值在任何时间点有效的标志。当您使用值作为字符串时,perl 会计算该字符串值并设置一个标志,将其标识为有效。 (其他操作,例如加 1 会使字符串值无效。)当您打印某些内容时,您(毫不奇怪)将其用作字符串。您可以使用 Devel::Peek 来查看这一点。
结果是
请注意,在第二个转储输出中,PV 槽(字符串值)已被填充,并且 pPOK 标志已添加到 FLAGS 下。
所以,是的,
print
具有某种副作用,尽管在正常情况下您永远不会注意到。version->parse()
似乎需要一个字符串参数,但不会触发字符串语义。鉴于version
更喜欢使用 XS 实现,这可能是那里的错误,而不是 Perl 中的错误。请注意,复制捕获数据会导致问题消失:结果:
Scalar values in Perl can be a number and a string at the same time. An SV object (SV = Scalar Value) has slots for integer, float, and string values and flags identifying which of those values are valid at any point in time. When you use a value as a string perl calculates the string value and sets a flag identifying it as valid. (Other operations, like adding 1 would invalidate the string value.) When you print something you're (unsurprisingly) using it as a string. You can see this using Devel::Peek.
The result is
Note that in the second dump output the PV slot (string value) has been populated and the pPOK flag has been added under FLAGS.
So, yes,
print
has side-effects of a sort although under normal circumstances you should never notice.version->parse()
appears to expect a string argument but isn't triggering string semantics. Given thatversion
prefers to use an XS implementation, it's probably a bug there rather than in perl. Note that making a copy of the capture data causes the problem to disappear:Result:
看起来像是 version::parse 中的一个错误,它没有正确触发传入参数的 get magic 。
查看代码可以发现 CPAN 和核心“版本”中存在同样的问题;它在处理 get magic 之前很久就检查 SvOK 。不幸的是,这将涉及模块代码和 Perl 核心的修复。
Looks like a bug in version::parse, that it isn't properly triggering get magic on the incoming parameter.
Looking at the code shows the same problem in the CPAN and core "versions"; it's checking SvOK long before handling get magic. Unfortunately, this will involve a fix both in the module code and the perl core.
这在 MacOS X 10.6.8 上使用 Perl 5.14.1 进行重现,使用“版本”0.91 的 XS 实现(即版本 0.91)...
但是,这是
version::vxs
(XS 实现),而不是version::vpp
(纯 Perl)实现。正如你所展示的那样,这失败了。当我编译纯 Perl 版本(
perl Makefile.PL --perl_only
,如 README 文件中所述)并对其进行测试时,它工作正常:我认为您可以明智地 在 CPAN RT 上举报(作者是 JPEACOCK)。作为解决方法,手动安装纯 Perl 版本并删除 XS 版本(因为代码首先查找 XS 代码 - 请参阅
version-0.91/lib/version.pm
)。如果您真的很勇敢,请考虑找出真正的错误是什么。This reproduces with Perl 5.14.1 on MacOS X 10.6.8, using the XS implementation of 'version' 0.91 (that's version version 0.91)...
However, it is a bug in the
version::vxs
(XS implementation), not theversion::vpp
(pure Perl) implementation.That fails as you showed. When I compiled the pure Perl version (
perl Makefile.PL --perl_only
, as mentioned in the README file), and tested it, it worked correctly:I think you could sensibly report this on CPAN RT (the author is JPEACOCK). As a workaround, manually install the pure Perl version and remove the XS version (because the code looks for the XS code first - see
version-0.91/lib/version.pm
). If you're really brave, consider working out what the actual bug is.不总是这样吗?你提出一个问题,然后找到答案!
此代码:
工作正常。请注意,$1 已在此处进行字符串化。
尽管如此,这仍然留下了一个有趣的观察结果:打印变量似乎会永久地将其字符串化!
Isn't it always the way; you ask a question and then find the answer!
This code:
Works correctly. Note that $1 has been stringified here.
Still, that leaves an interesting observation: that printing a variable seems to permanently stringify it!
我不知道版本号背后的特殊魔力,但是通过重载,您几乎可以给字符串化带来任何副作用。
I don't know the particular magic behind version numbers, but with
overload
you can give practically any side-effect you want to stringification.