我应该使用$ _ [0]还是复制Perl中的参数列表?

问题描述:

如果我通过散列子:

parse(\%data); 

我应该使用$_[0]变量第一或者是好的,保持访问$_[0]每当我想从哈希的元素?澄清:

sub parse 
{ $var1 = $_[0]->{'elem1'}; 
    $var2 = $_[0]->{'elem2'}; 
    $var3 = $_[0]->{'elem3'}; 
    $var4 = $_[0]->{'elem4'}; 
    $var5 = $_[0]->{'elem5'}; 
} 
# Versus 
sub parse 
{ my $hr = $_[0]; 
    $var1 = $hr->{'elem1'}; 
    $var2 = $hr->{'elem2'}; 
    $var3 = $hr->{'elem3'}; 
    $var4 = $hr->{'elem4'}; 
    $var5 = $hr->{'elem5'}; 
} 

是第二个版本更正确的,因为它没有继续访问参数数组,还是Perl的最终interpereting无论如何他们以同样的方式?

在这种情况下,没有区别,因为您传递的是散列引用。但如果通过标量将有差异:

sub rtrim { 
    ## remove tailing spaces from first argument 
    $_[0] =~ s/\s+$//; 
} 
rtrim($str); ## value of the variable will be changed 

sub rtrim_bugged { 
    my $str = $_[0]; ## this makes a copy of variable 
    $str =~ s/\s+$//; 
} 
rtrim($str); ## value of the variable will stay the same 

如果您传递哈希引用,则只创建引用的副本。但哈希本身将是相同的。所以如果你关心代码可读性那么我建议你为你的所有参数创建一个变量。例如:

sub parse { 
    ## you can easily add new parameters to this function 
    my ($hr) = @_; 

    my $var1 = $hr->{'elem1'}; 
    my $var2 = $hr->{'elem2'}; 
    my $var3 = $hr->{'elem3'}; 
    my $var4 = $hr->{'elem4'}; 
    my $var5 = $hr->{'elem5'}; 
} 

此外,更多描述性变量名称也会改善您的代码。

其同样,虽然第二个更清晰

由于他们的工作,都是精细,通常的做法是shift关闭参数。

sub parse { my $hr = shift; my $var1 = $hr->{'elem1'}; } 
+3

我不会说“这是常见的做法。”这实际上是一场纯Perl的圣战。 – 2009-11-18 18:07:58

+1

my($ one,$ two)=((shift),(shift));或者我的($ 1,$ 2)= @_; ? – user105033 2009-11-18 18:16:04

+4

'$ hr - > {elem1}'或$ $$ hr {elem1}'很帅气。 $$ hr - > {elem1}'不起作用。 – friedo 2009-11-18 19:30:52

您是微型优化;尽量避免这种情况。去任何最可读/可维护的。通常这是你使用词法变量的地方,因为它的名字表明它的目的...但是如果你使用的名字如$data$x这显然不适用。

就技术细节而言,对于大多数目的,您可以通过计算perl将使用的基本操作的数量来估计所花费的时间。对于你的$_[0],非词汇数组变量中的元素查找需要多个操作:一个获取glob,一个获取glob的数组部分,一个或多个获取索引(只有一个用于常量),以及一个查找元素。另一方面是$hr是单个操作。为了迎合@_的直接用户,有一种优化可以将$_[0]的操作减少为单个组合操作(当索引介于0和255之间时),但在您的情况下不会使用它,因为hash-deref上下文数组元素查找需要额外的标志(以支持自动生成),并且该优化操作不支持该标志。

总之,使用词汇将会更加可读,并且(如果您多次使用它)不知不觉会更快。

对于shift效率VS直接访问@_的一般讨论,请参见:

至于你具体的代码,我会用shift,但用散列片简化数据提取:

sub parse 
{ 
    my $hr = shift; 
    my ($var1, $var2, $var3, $var4, $var5) = @{$hr}{qw(elem1 elem2 elem3 elem4 elem5)}; 
} 

我会假设这个方法对这些变量做了一些其他的操作,这使得将它们保存在不同的变量中是值得的(也许哈希是只读的,并且在插入其他数据之前需要进行一些修改? ) - 否则为什么不把它们留在他们开始的hashref?

+5

散列片+1,世界遗忘的奇迹。 – 2009-11-18 19:36:16

+0

将项目放入变量中的一个很好的理由是提供了'strict'vars''提供的错字保护。你也可以通过'Hash :: Util :: lock_keys'来锁定你的哈希键。 – daotoad 2009-11-18 20:09:15

+0

我的功能完全不是我所做的,我只是举了一个例子。 – user105033 2009-11-18 21:07:43

我的规则是我尽量不要在比两个语句更长的子例程中使用$_[0]。之后,所有东西都得到一个用户定义的变量。

你为什么要把所有的散列值复制到变量中?只要将它们留在它们所属的散列中即可。这比你想的要好得多。

+1

我只在两种情况下使用'$ _ [0]':类访问器(符合你的“几条语句”规则)以及罕见的情况下,我想修改参数并需要保留别名。 – 2009-11-18 20:49:41

+0

@Michael Carman:如果你愿意,你可以避免使用'$ _ [0]'并且明确地记录你的就地修改,像这样:'perl -Mstrict -wle'sub arg_aliases {\ @_} sub foo {my $ arg_aliases =&arg_aliases;我($ foo)= @_;打印“foo是$ foo”; $ arg_aliases - > [0] =“plugh”} my $ foo =“xyzzy”; FOO($ foo的);打印“foo现在是$ foo”'' – ysth 2009-11-19 01:38:41

+0

但生病了 – ysth 2009-11-19 01:39:39