以下是一些谨慎使用@_
事项的示例。
1. Hash-y 参数
有时您想编写一个可以获取键值对列表的函数,但其中一个是最常见的用途,您希望它无需键即可使用。例如
sub get_temp {
my $location = @_ % 2 ? shift : undef;
my %options = @_;
$location ||= $options{location};
...
}
所以现在如果你用奇数个参数调用函数,第一个是位置。这允许get_temp('Chicago')
或get_temp('New York', unit => 'C')
什至get_temp( unit => 'K', location => 'Nome, Ak')
。对于您的用户来说,这可能是一个更方便的 API。通过移动奇数参数,now@_
是一个偶数列表,并且可以分配给一个散列。
2. 调度
假设我们有一个类,我们希望能够按名称调度方法(可能 AUTOLOAD 可能有用,我们将手动滚动)。也许这是一个命令行脚本,其中参数是方法。在这种情况下,我们定义了两种调度方法,一种是“干净的”,一种是“脏的”。如果我们用-c
旗子跟注,我们会得到干净的旗子。这些方法通过名称找到方法并调用它。不同的是如何。肮脏的将自己留在堆栈跟踪中,干净的必须更加切割,但调度时不会出现在堆栈跟踪中。我们制作了一种death
方法,可以为我们提供该痕迹。
#!/usr/bin/env perl
use strict;
use warnings;
package Unusual;
use Carp;
sub new {
my $class = shift;
return bless { @_ }, $class;
}
sub dispatch_dirty {
my $self = shift;
my $name = shift;
my $method = $self->can($name) or confess "No method named $name";
$self->$method(@_);
}
sub dispatch_clean {
my $self = shift;
my $name = shift;
my $method = $self->can($name) or confess "No method named $name";
unshift @_, $self;
goto $method;
}
sub death {
my ($self, $message) = @_;
$message ||= 'died';
confess "$self->{name}: $message";
}
package main;
use Getopt::Long;
GetOptions
'clean' => \my $clean,
'name=s' => \(my $name = 'Robot');
my $obj = Unusual->new(name => $name);
if ($clean) {
$obj->dispatch_clean(@ARGV);
} else {
$obj->dispatch_dirty(@ARGV);
}
所以现在如果我们./test.pl
调用死亡方法
$ ./test.pl death Goodbye
Robot: Goodbye at ./test.pl line 32
Unusual::death('Unusual=HASH(0xa0f7188)', 'Goodbye') called at ./test.pl line 19
Unusual::dispatch_dirty('Unusual=HASH(0xa0f7188)', 'death', 'Goodbye') called at ./test.pl line 46
但我们dispatch_dirty
在跟踪中看到。相反,如果我们调用./test.pl -c
,我们现在使用干净的调度程序并获取
$ ./test.pl -c death Adios
Robot: Adios at ./test.pl line 33
Unusual::death('Unusual=HASH(0x9427188)', 'Adios') called at ./test.pl line 44
这里的关键是goto
(不是邪恶的 goto),它接受子例程引用并立即将执行切换到该引用,使用当前的@_
. 这就是为什么我必须unshift @_, $self
让调用者为新方法做好准备。