为什么在这个Perl示例中print后面的第一个左括号前面有一个+

  • 本文关键字:第一个 有一个 前面 print Perl perl
  • 更新时间 :
  • 英文 :


最近我遇到一个类似的语句

print +( map { $_ + 1 } @$_ ), "n" for @$array; # <- AoA

我以前从未见过+运算符与这样的打印一起使用。运行该语句,不难推断它在做什么。但是我很难找到以这种方式使用的+运算符的文档。

my @tab = (
[1,2,3,4],
[qw(a b c d)],
);
my $test = "(", +( map { qq( >>$_<< ) } @$_ ), ")n" for @tab;
print $test;
my @test = "(", +( map { qq( >>$_<< ) } @$_ ), ")n" for @tab;
print @test;
my %test = "(", +( map { qq( >>$_<< ) } @$_ ), ")n" for @tab;
print %test;

以上三个测试都会产生警告:Useless use of a constant ()) in void contextUse of uninitialized value用于scalar测试,Odd number of elements in hash assignment用于arrayhash测试。如果能够将输出的语句存储在scalar中,那就太好了。我知道我可以使用下面这样的for循环在scalar中存储一个相同的字符串。

print "(", +( map { qq( >>$_<< ) } @$_ ), ")n" for @tab;
my $out = '';
for (@tab) {
    $out .= "(" . ( join '', map { qq( >>$_<< ) } @$_ ) . ")n";
}   
print $out;
# output ...
( >>1<<  >>2<<  >>3<<  >>4<< )
( >>a<<  >>b<<  >>c<<  >>d<< )
---
( >>1<<  >>2<<  >>3<<  >>4<< )
( >>a<<  >>b<<  >>c<<  >>d<< )

为什么我不能将语句存储在任何变量中或测试其type。我想详细了解使用+运算符时内置print的实际情况。

EDIT:我相信我最初的帖子有点令人困惑,我确实想了解更多关于print使用的+运算符的信息,但我真正想要的是如何将缩写for语句的每次迭代存储到标量字符串中-经过一些测试,我找到了一种方法。。。

use strict;
use warnings;
my @a = ([1,2,3],[qw/a b c/]);
my $one = '';
$one .= "(" . ( join '', map { " >>$_<< " } @$_ ) . ")n" for @a;
print $one;
# output ...
( >>1<<  >>2<<  >>3<< )
( >>a<<  >>b<<  >>c<< )

我想你在这里问了两个问题,所以我会尽我所能回答这两个问题。。。首先,你指的是来自perlop 的一元"+"运算符

一元"+"没有任何影响,即使对字符串也是如此。在语法上,将函数名与带括号的表达式分离是很有用的,否则表达式将被解释为函数参数的完整列表。

为了进一步了解印刷声明中到底发生了什么,我发现对佩尔曼的解释非常好。

文档解释了+将print函数与圆括号分开(并且告诉perl这些圆括号不是包装print函数参数的圆括号

这可能会让您满意,但如果您感兴趣,可以使用B::Deparse模块询问perl如何理解以下代码片段:

print +(stat $filename)[7];

我们将该内容保存在plus.pl文件中,并运行perl-MO=Deparse plus.pl。结果是:

print((stat $filename)[7]);

希望这有帮助!

编辑

详细解释为什么不能使用相同的命令打印该序列并将其分配给标量可能超出了这个问题的范围,但我将尝试简要解释。。。注意,如果我错了,我希望得到纠正,我已经通过使用它编写代码,而不是通过阅读关于其内部工作的perl文档,了解了这是如何工作的:)使用打印语句

print "(", +( map { qq( >>$_<< ) } @$_ ), ")n" for @tab;

perl将其解释为

(print "(", +( map { qq( >>$_<< ) } @$_ ), ")n") for @tab;

也就是说,它对您想要打印的所有内容进行分组,并为@tab中的每个元素执行它。然而,使用您的标量分配

my $test = "(", +( map { qq( >>$_<< ) } @$_ ), ")n" for @tab;

perl正在对")\n"执行for @tab代码,因此会发出Useless use of a constant ()) in void context警告。要想做你想做的事,你需要明确你想要for’d

my $test; ( $test .= "(" . join ('', ( map { qq( >>$_<< ) } @$_)) . ")n") for @tab; print $test;

应该会得到你想要的东西。请注意整个赋值周围的括号,以及映射前省略的一元"+",这已不再必要。

perldoc-f打印:

注意不要遵循打印带有左括号的关键字,除非需要相应的右括号以终止打印在所有参数周围加括号(或插入一个"+",但这看起来不太好)。

在这种情况下,如果不希望map使用"n",则必须在map { $_ + 1 } @$_周围加上括号。但是,当你这样做的时候,你会遇到上面描述的情况,除非你在左括号之前放一个+,这样+(map { $_ + 1 } @$_)就变成了一个要打印的参数,而不是(map { $_ + 1 } @$_)被解释为完整的参数列表。

如果你有

print ( map { $_ + 1 } @$_ ), "n" for @$array;

上面右括号后面的逗号将被解释为逗号运算符。print只会打印数字,而不是换行符:

$perl-we'$array=[[1,2,3]];print(映射{$_+1}@$_),"\n"表示@$array;'print(…)被解释为-e行1处的函数。在-e第1行的void上下文中无用地使用了常量("\n")。234%

print进行了评估。作为副作用,它打印数字。print的返回值被丢弃,并且表达式的值变为"n"。由于该值未分配给任何对象,因此会收到警告。基本上,代码最终看起来像:

"n" for @$array;

除了调用CCD_ 36的副作用之外。

如果你想把循环的输出存储在一个变量中,你可以这样做:

my $string;
$string .= sprintf( "(%s)n", join('', map {$_ + 1} @$_) ) for @tab;

相关内容

最新更新