14

我试图围绕 Perl 处理对print.

为什么会这样

print $fh $stufftowrite

按预期写入文件句柄,但是

print($fh, $stufftowrite)

而是将文件句柄写入?STDOUT

我的猜测是它与以下文档中的警告有关print

注意不要在 print 关键字后面加上左括号,除非您希望相应的右括号终止 print 的参数;在所有参数周围加上括号(或插入一个 + ,但这看起来不太好)。

我应该习惯第一种形式(这对我来说似乎不正确,来自所有在函数参数周围使用括号的语言),还是有办法告诉 Perl 做我想做的事?

到目前为止,我已经在第一个、第二个和两个参数周围尝试了很多括号组合,但没有成功。

4

4 回答 4

18

在名单上

该结构的bareword (LIST1), LIST2意思是“将函数bareword应用于参数LIST1”,虽然bareword +(LIST1), LIST2可以,但不一定意味着“应用于bareword组合列表的参数LIST1, LIST2”。这对于分组参数很重要:

my ($a, $b, $c) = (0..2);
print ($a or $b), $c;  # print $b
print +($a or $b), $c; # print $b, $c

前缀+也可以用来区分 hashrefs 和 block,以及函数和 barewords,例如在下标 hash 时:$hash{shift}返回shift元素,同时$hash{+shift}调用函数shift并返回 value 的 hash 元素shift

间接语法

在面向对象的 Perl 中,您通常使用箭头语法调用对象上的方法:

$object->method(LIST);   # call `method` on `$object` with args `LIST`.

但是,可以但推荐使用将动词放在首位的间接表示法:

method $object (LIST);   # the same, but stupid.

因为类只是它们自身的实例(在句法意义上),你也可以在它们上调用方法。这就是为什么

new Class (ARGS);  # bad style, but pretty

是相同的

Class->new(ARGS);  # good style, but ugly

但是,这有时会混淆解析器,因此不建议使用间接样式。

但它确实暗示了 print 的作用:

print $fh ARGS

是相同的

$fh->print(ARGS)

实际上,文件句柄$fh被视为类的对象IO::Handle

(虽然这是一个有效的句法解释,但它并不完全正确。它IO::Handle本身的源代码使用了这一行print $this @_;。打印函数就是这样定义的。)

于 2012-12-01T12:25:00.753 回答
15

看起来你有一个错字。您在第二个打印语句中的文件句柄和参数之间放置了一个逗号。如果你这样做,文件句柄将被视为一个参数。这似乎只适用于词法文件句柄。如果使用全局文件句柄完成,则会产生致命错误

No comma allowed after filehandle at ...

因此,要清楚,如果您绝对必须为您的 加上括号,请print执行以下操作:

print($fh $stufftowrite)

虽然我个人更喜欢不使用括号,除非我必须这样做,因为它们只会增加混乱。

于 2012-12-01T11:54:38.563 回答
9

现代 Perl 书在第 11 章(“要避免的事情”)的“间接表示法标量限制”部分中指出:

语法的另一个危险是解析器需要一个单一的标量表达式作为对象。打印到存储在聚合变量中的文件句柄似乎很明显,但事实并非如此:

# DOES NOT WORK AS WRITTEN
say $config->{output} 'Fun diagnostic message!';

Perl 将尝试在 $config 对象上调用 say。 print, close, 和say——所有在文件句柄上运行的内置函数——以间接方式运行。当文件句柄是包全局变量时这很好,但是词法文件句柄(文件句柄引用)使间接对象语法问题变得明显。为了解决这个问题,消除产生预期调用者的子表达式的歧义:

say {$config->{output}} 'Fun diagnostic message!';

当然,print({$fh} $stufftowrite)也是可以的。

于 2012-12-01T12:27:16.277 回答
3

print这就是定义的语法的方式。真的就是这么简单。没有什么可以解决的。如果在文件句柄和其余参数之间放置逗号,则表达式将被解析为print LIST而不是print FILEHANDLE LIST. 是的,这看起来真的很奇怪。这真的很奇怪。

不被解析为的方法print LIST是提供一个可以合法解析为的表达式print FILEHANDLE LIST。如果你想要做的是在参数周围加上括号,print让它看起来更像一个普通的函数调用,你可以说

print($fh $stufftowrite); # note the lack of comma

你也可以说

(print $fh $stufftowrite);

如果您尝试做的是print从周围的代码中删除表达式。关键是包含逗号会改变解析。

于 2012-12-05T05:22:40.707 回答