【问题标题】:perl string interpolation when using the package delimiter使用包分隔符时的 perl 字符串插值
【发布时间】:2015-05-12 14:56:49
【问题描述】:

我正在与一些遗留的 perl 作斗争,如下所示:

sub UNIVERSAL::has_sub_class {
    my ($package,$class) = @_;
    my $all = all_packages();
    print "$package - $class", "\n";
    print "$package::$class", "\n";
    return exists $all->{"$package::$class"};
}

在两个不同的系统、两个不同的 PERL 安装/版本上,此代码的行为不同,即 "$package::$class" 构造在一个系统上被正确解析为正确的包名称,但在另一个系统上却没有。

在两个不同的系统上运行has_sub_class 时可以看到以下不同的print 输出:

# print output on system 1 (perl v5.8.6):
webmars::parameter=HASH(0xee93d0) - webmars::parameter::date
webmars::parameter::date

# print output on system 2 (perl v5.18.1):
webmars::parameter=HASH(0x251c500) - webmars::parameter::date
webmars::parameter=HASH(0x251c500)::webmars::parameter::date

您知道在 perl v5.8.6 和 perl v5.18.1 之间是否有任何字符串插值更改可能导致这种行为?或者我应该去别的地方看看?我真的尝试过用谷歌搜索并阅读 perl 更改说明,但找不到任何感兴趣的内容。

由于我对 perl 的了解有限,我尝试获取可以重现我遇到的问题的最小代码段。我想出了以下我希望是相关的:

# system 1 (perl v5.8.6):
$ perl -e 'my %x=(),$x=bless(\%x),$y='bar';print "$x::$y\n";'
bar

# system 2 (perl v5.18.1):
$ perl -e 'my %x=(),$x=bless(\%x),$y='bar';print "$x::$y\n";'
main=HASH(0xec0ce0)::bar

输出不同!有什么想法吗?

【问题讨论】:

  • perl -Mstrict -we 'my %x=(),$x=bless(\%x),$y='bar';print "$x::$y\n";'
  • 很容易成为在发布之间的 6 年内修复的错误 :)。但是这样简洁的 MCVE 做得很好!

标签: perl


【解决方案1】:

更短的演示:

($x::, $x) = (1,2);  print "$x::$x"

$ perl5.16.3 -e '($x::, $x) = (1,2);  print "$x::$x"'
12

$ perl5.18.1 -e '($x::, $x) = (1,2);  print "$x::$x"'
2::2

越来越暖和了。

$ perl5.16.3 -MO=Concise =e 'print "$x::$x"'
8  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
7     <@> print vK ->8
3        <0> pushmark s ->4
-        <1> ex-stringify sK/1 ->7
-           <0> ex-pushmark s ->4
6           <2> concat[t3] sK/2 ->7
-              <1> ex-rv2sv sK/1 ->5
4                 <#> gvsv[*x::] s ->5          <-     $x::
-              <1> ex-rv2sv sK/1 ->6
5                 <#> gvsv[*x] s ->6            <-     $x
-e syntax OK

$ perl5.18.1 -MO=Concise -e 'print "$x::$x"'
a  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
9     <@> print vK ->a
3        <0> pushmark s ->4
-        <1> ex-stringify sK/1 ->9
-           <0> ex-pushmark s ->4
8           <2> concat[t4] sKS/2 ->9
6              <2> concat[t2] sK/2 ->7
-                 <1> ex-rv2sv sK/1 ->5
4                    <#> gvsv[*x] s ->5         <-     $x
5                 <$> const[PV "::"] s ->6      <-     "::"
-              <1> ex-rv2sv sK/1 ->8
7                 <#> gvsv[*x] s ->8            <-     $x
-e syntax OK

TL;博士。 v5.16 将"$x::$x" 解析为$x:: . $x。 v5.18 为$x . "::" . $x。我在delta docs 中没有看到任何明显提及此更改的内容,但我会继续寻找。

【讨论】:

  • 确实,代码中似乎有一个错误,由于 "$x::$x" 解析为 $x:: . $x,而被静音,即 "$package::$class" 将寻找 $package:: 而不是 $package并最终用字符串中的 `` 替换它,因为它是未定义的。
  • 将其重写为 ${package}::$class 以使其在任何版本的 perl 中工作。
【解决方案2】:

所以,我的快速测试证实了这个问题 - 使用

perl -Mstrict -we 'my %x=(),$x=bless(\%x),$y="bar";print "$x::$y\n";'

(在您的版本中,我收到了关于“bar”的简单警告)。

我在 5.8.8 中遇到的错误是“在连接中使用未初始化的值”。

不同之处似乎在于,当我使用perl -MO=Deparse 运行时,我得到:

my ( %x ) = ();
my $x = bless ( \%x );
my $y = 'bar';
print "$x::$y\n";

如果我在 5.20.2 上运行,我会得到:

my ( %x ) = ();
my $x = bless ( \%x );
my $y = 'bar';
print "${x}::$y\n";

所以是的,解析相同代码的方式发生了变化。但我不完全确定这对你有什么帮助,除了可能启发你了解发生了什么?

【讨论】:

  • 它确实对我理解问题出在哪里很有帮助,是 perl 解释器还是代码中的问题。在这种情况下,它是两者的结合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
相关资源
最近更新 更多