脱引用(dereference)并不是只能用在引用上,返回引用的函数也能使用。如:

sub foo { my $a = 10; return \$a; }
print ${foo()};      # 返回10
print "${foo()}";    # 甚至在字符串替换中也能用!

两个相邻的下标之间可以省去 -> 。如:

print $sue{children}->[1]->{age};
print $sue{children}[1]{age};     # 与上一条语句相同

将字符串当作变量名的行为叫做符号引用:

$a = "x"; $x = 10; print $$a     # 输出10

注意符号引用只能引用到全局变量,用my声明过的就引用不到了。使用use strict可以禁止符号引用。


模拟二维数组(参考第2条):

$array = ( [1, 2], [3, 4] );  print $a[1][0];

类型团(typeglob):只有全局变量才有typeglob,用my声明的词法变量不在typeglob内。 可以通过typeglob赋值来给变量添加别名:

@a = (1, 2, 3);
*b = *a;       # 现在@b = (1, 2, 3)

引用可以赋值给typeglob,因此可以有以下用法:

选择性别名:

*b = \$a;      # 这样 $b 是 $a 的别名,但@b 不是 @a的别名

常量

*PI = \3.14159;   # 赋值之后 $PI 即为常量,不能修改

I/O重定向:也是typeglob的应用之一,如 open F, “>/tmp/x”; *STDOUT = *F; # 将STDOUT变成F的别名 print “Hello, world!\n”; # print想输出到STDOUT,实际上却输出到了F


需要将文件句柄作为参数使用时,尽量不要用typeglob,而是用FileHandle模块:

# 不推荐的做法
open F, "/tmp/sesame";
read_and_print(*F); 
sub read_and_print {
  local (*G) = @_;
  while <G> { print; }
}

# 推荐这样做
my $f = new FileHandle;
open $f, "/tmp/sesame";
read_and_print($f);
sub read_and_print {
  my ($f) = @_;
  while <$f> { print; }
}

匿名函数的定义和调用:

$foo = sub { print "Hello, $_[0]!\n"; };    # 注意末尾要有分号
&$foo("world");       # 可以用&符号来调用
$foo->("world");      # 也可以用->调用

如何抛出自己不想处理的异常:

eval { .... }; if ($@ =~ /.../) { 处理异常; } else { die; }     # 不带参数的die相当于die $@ ___________________

正则表达式中的 /e 修饰词并不等于eval(虽然很像)。如:

$str = "10/0";
$str =~ s/(\d+)\/(\d+)/$1\/$2/e;
print $str;

结果 s 那一行会打印出零除错误,而不是将错误放到 $@ 中。要想捕获错误,需要用eval 将s括起来。


设置等待超时一般都这样做:

local $SIG{ALRM} = sub { die "TIMEOUT"; };
eval {
  alarm(10); $input = <>; alarm(0);
};
if ($@ =~ /TIMEOUT/) { ... }

注意这里alarm(10)一定要放在eval内。否则,万一程序执行完alarm后发生任务切换,而程序再次获得时间片时,ALRM信号已经发生, 这时程序还没有执行到eval内就产生die,程序就会退出。


存取包的符号表: foreach $name (%Foo::) ...


搜索@ISA数组是深度优先的。


Symbol模块可以生成typeglob。使用方法:

use Symbol;
$foo = Symbol::gensym();
${*$foo} = "Hello, world!";    # 使用标量部分
@{*$foo} = (1, 2);             # 使用数组部分
open $foo, "/tmp/foo";         # 当作文件句柄使用