Perl的隐藏特性是什么?

143

Perl 中有哪些十分实用但却比较晦涩的语言特性,你能够利用它们完成有用的工作吗?

指南:

  • 尽可能限制回答范围在 Perl 核心而非 CPAN 上
  • 请给出一个例子和简短的描述

其他编程语言中也有的隐藏特性:

(这些来自于 Corion 的回答)

  • C
    • Duff's 设备
    • 可移植性和标准性
  • C#
    • 对空格分隔列表和字符串使用引号
    • 可别名的命名空间
  • Java
    • 静态初始化器
  • JavaScript
    • 函数是一等公民
    • 块级作用域和闭包
    • 通过变量间接调用方法和访问器
  • Ruby
    • 通过代码定义方法
  • PHP
    • 无处不在的在线文档
    • 魔术方法
    • 符号引用
  • Python
    • 一行内交换值
    • 能够替换甚至是核心函数的功能实现

其他隐藏特性:

运算符:

引用结构:

语法和名称:

模块、编译指令和命令行选项:

变量:

循环和流程控制:

正则表达式:

其他特性:

其他技巧和元回答:


另请参阅:


大多数这些功能都在日常使用中,一些出现在大多数Perl脚本中,而大多数列在“其他”下的仍然源自其他语言,将它们称为“隐藏”的更改是问题意图的误解。 - reinierpost
78个回答

15
循环中的continue子句。它将在每个循环的底部执行,即使是被next跳过的循环也会执行。
while( <> ){
  print "top of loop\n";
  chomp;

  next if /next/i;
  last if /last/i;

  print "bottom of loop\n";
}continue{
  print "continue\n";
}

13

m//运算符有一些不太常见的特殊情况:

  • 如果您将?用作分隔符,它只会匹配一次,除非您调用reset
  • 如果您将'用作分隔符,则模式不会被插值。
  • 如果模式为空,则使用上一个成功匹配的模式。

2
这些更像是隐藏的陷阱而不是隐藏的功能!我不认识任何喜欢它们的人。在一段时间前的p5p线程上讨论了一个假设的m/$foo/r标志的有用性,其中/r将意味着没有插值(字母并不重要),因为没有人能记住单引号的事情。 - dland
2
@dland:同意;我会称之为隐藏的“缺陷”,并且永远不会在生产代码中使用它们。 - Michael Carman
7
我无法想象一个Perl程序员会忘记(甚至无法猜测)单引号表示无插值。这种用法在语言中几乎是普遍的,所以我更倾向于“期望”是如此... - Sundar R
如果模式为空并且最后一个成功的匹配是使用/o修饰符编译的,则从那时起,它将停留在该模式上。 - davidnicol
1
我认为空模式的行为已被弃用。主要是因为像 m/$foo/ 这样的模式在 $foo 为空时会变成一个讨厌的 bug。 - Matthew S
@sundar:是的,基本上是这样。但是 qq'...'q"..." 会让你感到困惑,因为它们产生了认知失调,并且引号并没有覆盖实际发生的事情。不过 qx'...' 的行为是正确的。 - tchrist

13
while(/\G(\b\w*\b)/g) {
     print "$1\n";
}

\G锚点。它非常强大


3
它表示先前匹配的结尾位置。 - Dave Sherohman
1
但是你必须在标量上下文中调用你的正则表达式。 - davidnicol
@davidnicol:上面的代码是可以正常工作的。你能澄清一下你的意思吗? - J.J.

12

空文件句柄钻石操作符<>在构建命令行工具时很有用。它的作用类似于<FH>从句柄中读取,但是它会神奇地选择先被找到的内容:命令行文件名或STDIN。引自perlop:

while (<>) {
...         # code for each line
}

4
它也遵循了UNIX的语义,使用“-”表示“从标准输入读取”。 因此,您可以执行perl myscript.pl file1.txt - file2.txt,然后perl会处理第一个文件,然后是标准输入,最后是第二个文件。 - Ryan C. Thompson
你可以在自己的对象(<$var>)上overload <>操作符,使其像迭代器一样工作。但是它在列表上下文中不会按照你期望的方式工作。 - dolmen

11
rename("$_.part", $_) for "data.txt";

将data.txt.part重命名为data.txt,而无需重复自己。


11

特殊代码块,如BEGINCHECKEND。它们来自于Awk,但在Perl中的工作方式有所不同,因为它不是基于记录的。

BEGIN块可用于指定一些解析阶段的代码; 当您执行语法和变量检查perl -c时,也会执行它。例如,加载配置变量:

BEGIN {
    eval {
        require 'config.local.pl';
    };
    if ($@) {
        require 'config.default.pl';
    }
}

10

有点难以理解的是波浪线波浪线“运算符”,它强制进行标量上下文。

print ~~ localtime;

是相同的。
print scalar localtime;

与不同

print localtime;

5
这个尤其晦涩难懂,因为perl5.10.0还引入了“智能匹配运算符”~~,可以进行正则表达式匹配,可以查看是否包含在数组中等操作。 - moritz
这并不是晦涩难懂,而是混淆(对于编程竞赛和JAPH很有用)。 - Michael Carman
这不是正确的!~~ 对于引用来说并不安全!它会将其字符串化。 - Leon Timmermans
是的,字符串化是当引用被强制转换为标量上下文时发生的情况。这怎么会使“~~ 强制标量上下文”不正确呢? - Dave Sherohman
3
@Nomad Dervish:标量上下文并不等同于字符串化。例如,"$n = @a" 是标量上下文。"$s = qq'@a'" 是字符串化。关于引用,"$ref1 = $ref2" 是标量上下文,但不会字符串化。 - Michael Carman

9
输入记录分隔符可以设置为一个数字的引用,以读取固定长度的记录:
$/ = \3; print $_,"\n" while <>; # output three chars on each line

9

tie,将变量绑定的接口。


9
山羊脱口秀运算符*:
$_ = "foo bar";
my $count =()= /[aeiou]/g; #3

或者
sub foo {
    return @_;
}

$count =()= foo(qw/a b c d/); #4

它之所以有效,是因为在标量上下文中进行的列表赋值会产生被赋值列表中的元素数量。

* 注意,这实际上不是一个运算符。

那是最美(或最丑)的操作符。 - Chris Lutz

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