为什么在Perl示例中打印后的第一个左括号之前有一个+?

时间:2015-04-09 00:32:41

标签: 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测试的scalarOdd number of elements in hash assignmentarray测试的hash,能够将语句输出存储在{ {1}}。我知道我可以使用下面的for循环在scalar中存储一个相同的字符串。

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内置函数实际发生的情况。

  

编辑:我相信我原来的帖子有点令人困惑,我确实想了解更多关于与+一起使用的+运算符,但我真正想要的是如何将速记print语句的每次迭代存储到标量字符串中 - 经过一些测试后我找到了一种方法......

for

2 个答案:

答案 0 :(得分:5)

我想你在这里问过两个问题,所以我会尽可能地回答他们两个问题...... 首先,您指的是perlop

中的一元“+”运算符
  

一元“+”无论如何都没有效果,即使是在琴弦上也是如此。语法上有用的是将函数名与括号表达式分开,否则将被解释为函数参数的完整列表。

为了扩展print语句的确切内容,我发现perlmaven的解释非常好。

  

文档说明+将打印功能与括号分开(并告诉perl这些不是包装打印功能参数的括号。

     

这可能会让你感到满意,但是如果你有进一步的兴趣,你可以使用B :: Deparse模块询问perl它是如何理解这段代码片段的:

     

print +(stat $filename)[7];

     

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

     

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

希望这有用!

修改

详细解释为什么你不能使用相同的命令来打印那个序列并将它分配给标量可能超出了这个问题的范围,但我会试着简单解释一下...如果我对某些事情做错了,我会喜欢纠正,我已经通过使用这个来编写代码来理解这是如何工作的,而不是通过阅读其内部工作的perl文档:) 使用print语句

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;

应该得到你想要的东西。请注意整个作业的括号,以及在地图之前省略一元“+”,这是不再需要的。

答案 1 :(得分:4)

perldoc -f print

  

小心不要跟随               除非你想要,否则用左括号打印关键字               相应的右括号来终止参数               打印;在所有参数周围加上括号(或插入一个“+”,               但这看起来不太好。)

在这种情况下,您希望map使用"\n",您必须在map { $_ + 1 } @$_周围加上括号。但是,当你这样做的那一刻,你会遇到上述情况,除非你在左括号前放置一个+,以便+(map { $_ + 1 } @$_)成为一个打印的单个参数,而不是(map { $_ + 1 } @$_)被解释为完整的参数列表。

如果你有

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

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

$ perl -we '$array=[[1,2,3]];print ( map { $_ + 1 } @$_ ), "\n" for @$array;'
print (...) interpreted as function at -e line 1.
Useless use of a constant ("\n") in void context at -e line 1.
234%

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

"\n" for @$array;

除了调用print的副作用。

如果要将循环的输出存储在变量中,可以执行以下操作:

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