【问题标题】:How to tell perl to print to a file handle instead of printing the file handle?如何告诉 perl 打印到文件句柄而不是打印文件句柄?
【发布时间】:2012-12-01 11:53:18
【问题描述】:

我正在尝试围绕 Perl 处理对print 的参数进行解析的方式。

为什么会这样

print $fh $stufftowrite

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

print($fh, $stufftowrite)

文件句柄写入STDOUT

我的猜测是与print的文档中的警告有关:

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

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

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

【问题讨论】:

    标签: perl


    【解决方案1】:

    在列表中

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

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

    前缀+也可以用来区分hashrefs和blocks,以及functions和barewords,例如下标哈希时:$hash{shift}返回shift元素,而$hash{+shift}调用函数shift并返回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 @_; 行。打印函数就是这样定义的。)

    【讨论】:

    • 有没有办法在print $fh 'text' 被调用时得到通知?
    【解决方案2】:

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

    No comma allowed after filehandle at ...
    

    所以,要明确一点,如果您的print 绝对必须有括号,请执行以下操作:

    print($fh $stufftowrite)
    

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

    【讨论】:

      【解决方案3】:

      现代 Perl 书籍在 Chapter 11(“要避免的事情”)的“间接表示法标量限制”部分中陈述:

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

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        你也可以说

        (print $fh $stufftowrite);
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-07
          • 1970-01-01
          • 1970-01-01
          • 2015-04-13
          • 2012-08-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多