为什么普通字符串可以用作文件句柄?

时间:2015-01-28 15:15:10

标签: perl

我理解裸字可以用作文件句柄作为下面的第一行,即使不推荐它,但似乎第二行也可以。为什么普通字符串可以作为文件句柄工作?

perl -E"open FH, 'somefile.txt' or die 'open failed';print <FH>"
perl -E"open 'FH', 'somefile.txt' or die 'open failed';print <FH>"

更新:如果裸字FH与普通字符串&#39; FH&#39;相同,为什么以下行不起作用?

perl -E"open FH, 'somefile.txt';print <'FH'>"

3 个答案:

答案 0 :(得分:5)

以下两个陈述是相同的(如果没有名为FOO的子词):

my $x = FOO;
my $x = 'FOO';

因此,以下内容并非如此令人惊讶:

open FH, ...
open 'FH', ...

同样如此
print { FH } ...
print { 'FH' } ...

readline(FH)
readline('FH')

请注意,以下内容不等同

print FH ...
print 'FH' ...

因为解析器专门查看是否为print提供了一个裸字来确定参数的含义。

print LIST           # Prints list to selected handle
print BAREWORD LIST  # Prints list to specified handle
print { EXPR } LIST  # Prints list to specified handle

请注意,以下内容不等同

<FH>
<'FH'>

因为解析器专门查看一个裸字是否在<>内,以确定运算符的含义。

<BAREWORD>   # readline(BAREWORD)
<EXPR>       # glob(EXPR)

答案 1 :(得分:4)

询问perl解析器,

perl -MO=Deparse -E"open 'FH', 'somefile.txt' or die 'open failed';print <FH>"

use feature 'current_sub', 'evalbytes', 'fc', 'say', 'state', 'switch', 'unicode_strings', 'unicode_eval';
die 'open failed' unless open *FH, 'somefile.txt';
print <FH>;

所以它毕竟不使用字符串而是使用typeglob,但我认为这不是一个好习惯。

答案 2 :(得分:2)

该文件句柄不是裸词,而是类型glob 。这与Perl如何在符号表中存储包变量有关。我不想进入符号表以及它们是如何工作的,但它是Perl可以存储对打开文件句柄的引用的方式。

使用open BAR...存在多个问题。主要的是能够将类型glob 传递给子例程。想象一个子程序,我在其中取一个已经打开的文件,读取该文件,然后返回与正则表达式匹配的下一行。如何传入文件句柄?

my $line = grep_me ( BAR, $regex );    # That doesn't quite work.

通过将类型glob 的引用传递给标量变量, 是一种方法,但语法模糊而且相当混乱。

Perl 5中最大的功能之一是使用引用。如果您之前没有使用过Perl参考,请查看tutorial

试试这个程序:

use strict;
use warnings;
use feature qw(say);

my $real_file = "...";    # A real file with that name

open my $foo, "<", $real_file or die $!;
say "\$foo is a $foo";

这将打印出如下内容:

$foo is a GLOB(0x7feb0c0060e8)

这就是说$foo类型glob 引用。记得我说你可以通过引用它来将类型的glob 文件句柄传递给子程序吗? Perl 5已经为您提供了很好的引用,这使得传递该文件的句柄变得非常简单:

...
my $line = grep_me ( $foo, $regex );
...

sub grep_me {
     my $fh = shift;   # The file handle
     my $re = shift;   # The regular expression

     my $line;
     while ( $line = <$fh> ) {
        last if ( $line =~ /$re/ );
     }
     return $line;
}

使用标量引用也有其他优点:

  • 文件句柄是词法范围的,因此一旦$foo超出范围,文件句柄就会自动关闭。
  • 由于文件句柄是词法范围的,因此它在文件本身之外是不可用的。想象一下,如果我有一个使用文件的模块,如果我使用open FOO...,该文件句柄可用于使用我的模块的程序。如果我使用open my $foo...,则使用我的模块的程序无法通过我的模块操作文件。