为什么Perl的open()文档使用两种不同的FILEHANDLE风格?

9
打开函数的文档 展示了 open() 的语法如下:
  • open FILEHANDLE,EXPR
  • open FILEHANDLE,MODE,EXPR
  • open FILEHANDLE,MODE,EXPR,LIST
  • open FILEHANDLE,MODE,REFERENCE
  • open FILEHANDLE
在示例中,普通的以 $ 符号为前缀的变量用于文件句柄。请注意,不要修改 HTML 标签。
open(my $fh, "<", "input.txt")

同时还有使用裸字的示例:

open(FOO, "|tr '[a-z]' '[A-Z]'");

有一个问题是,在每种情况下,“我正在使用 _ _来处理文件句柄”,每种样式的名称是什么?另一个问题是,为什么他们在文档中开始使用裸词open()?看起来后者使用都不涉及普通文件名open()。在这些情况下,$前缀形式不可接受吗?


1
很好的问题,我一直被那个语法困扰着。 - qwwqwwq
除了这种方式之外,以任何其他方式执行open(STDOUT, "| less")都有点烦人。 - tchrist
2个回答

22

裸字形式本质上只是用于向后兼容的历史遗留问题。在新代码中使用词法变量几乎总是正确的事情。

→ 顺便提一下,$x 是一个词法标量变量,而FOO则是所谓的裸字。

细节/离题讨论

完整性起见,正如@Joe_Z在评论中指出的那样,词法文件句柄对象是“相对较新”的,作为Perl 5.005和5.6之间的重大重写的一部分(它们在这个版本号中甚至获得了整个数量级的增长...)。

然而,从技术上讲,裸字FOO(或者例如STDIN)被解释为一个单独的命名空间,仅用于文件句柄。由于文件句柄命名空间中没有符号(像$ @ % &),因此只有两种方法可以引用该命名空间中的文件句柄:

  • 您可以在某些函数的间接对象槽中引用它,例如print,它们(在幕后)会推断裸字必须引用文件句柄,出于历史原因;
  • 您可以使用类型球形,例如*FOO,它引用“任何命名空间中绑定到符号FOO的任何内容。
注意,在像 C 或 Scheme 这样的一些语言中,单个符号没有类型 sigils,因此所有符号只能以一种方式绑定(例如,在 C 中不能同时有名为 printf 的变量和名为 printf 的函数...通常),而在 Perl 或(例如)Common Lisp 中,同一个符号 foo 可以被绑定到许多不同的东西上;区别在于,在大多数情况下,Perl 实际上需要你使用 sigils 来消除“你指的是哪个 foo”这个模棱两可的问题。$foo、@foo = @foo[$x..$y]、$foo[$n]、%foo = @foo{$k1,$k2} = $foo{$k}、&foo 等。
然而,通过使用裸字作为文件句柄,您会失去一些功能:
显然,为了将它们局部或词法绑定(而不是全局绑定),您需要绑定每个命名空间中的每个符号,因为没有可用的 sigil。因此,my $foo 和 my @foo 可以存在于两个不同的临时存储区(作用域)中,其中一个可能比另一个长寿;但 my *foo 将包括这两个,以及文件句柄 foo(以及潜在的其他暗角案例,如格式说明符,尽管我不能保证)。
将裸字样式的文件句柄传递给函数等也极其困难。
总的来说,裸字继承了全局作用域的所有缺点,并且没有词法变量的任何优势。 perldoc perldata 有一个很好的“类型 glob 和文件句柄”部分,可能更清楚地解释了这些问题。我手头没有我的副本,但我相信 Camel 对这个主题进行了更详细的讨论。

5
使用词汇文件句柄是“正确的做法”,即使它是 Perl ,也有多种实现方式。 - Jonathan Leffler
因为我有点老派,偶尔在回答中使用全局风格的文件句柄,但总是会得到负面评论 :) 同意词法文件句柄更好,但这是一个难以改变的习惯! - Vorsprung
1
词法文件句柄是在 Perl 5.6 左右引入的。尽管如此,在我的工作场所,仍然有很多 Perl 代码可以追溯到 5.00x 时代。为了维护目的,了解这两种语法是很有好处的。我认为现在应该将旧的裸字文件句柄限制在文档中的“遗留”部分,除了 <STDIN> 和其他类似的情况。 - Joe Z

2

正如BPRocock所说,现在更倾向于使用my $x,而FOO被认为已经过时,因为FOO是一种全局变量,可能会与其他地方使用的名称冲突。还有另一个原因鼓励使用$x:在作用域结束时,$x将自动关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接