我应该使用$\u0还是复制Perl中的参数列表?

我应该使用$\u0还是复制Perl中的参数列表?,perl,hash,Perl,Hash,如果我将哈希传递给子对象: parse(\%data); 我应该先使用一个变量来$\u0],还是只要我想从散列中获取元素,就可以继续访问$\u0]?澄清: sub parse { $var1 = $_[0]->{'elem1'}; $var2 = $_[0]->{'elem2'}; $var3 = $_[0]->{'elem3'}; $var4 = $_[0]->{'elem4'}; $var5 = $_[0]->{'

如果我将哈希传递给子对象:

parse(\%data);
我应该先使用一个变量来
$\u0]
,还是只要我想从散列中获取元素,就可以继续访问
$\u0]
?澄清:

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最终以同样的方式解释它们?

第二个版本是一样的,尽管第二个版本更清楚,因为它们都可以工作,所以都很好,通常的做法是将参数移开

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

在这种情况下没有区别,因为您正在传递对散列的引用。但在传递标量的情况下,会有不同:

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'};
}

此外,更具描述性的变量名也将改进您的代码。

您正在进行微优化;尽量避免这样。选择最具可读性/可维护性的内容。通常情况下,这是一个使用词汇变量的地方,因为它的名称表明了它的用途……但是如果使用像
$data
$x
这样的名称,这显然不适用

就技术细节而言,在大多数情况下,您可以通过计算perl将使用的基本操作的数量来估计所花费的时间。对于
$\u0]
,非词法数组变量中的元素查找需要多个操作:一个用于获取全局,一个用于获取全局的数组部分,一个或多个用于获取索引(仅一个用于常量),一个用于查找元素<另一方面,code>$hr是一个单独的操作。为了迎合@的直接用户,有一个优化将
$[0]
的操作减少为一个单独的组合操作(当索引介于0和255之间(含0和255)时),但在您的情况下不使用它,因为哈希deref上下文需要在数组元素查找上附加一个标志(支持自生)且优化op不支持该标志


总而言之,使用词汇的可读性会更高,而且(如果你不止一次使用它)在不知不觉中会更快。

有关
shift
与直接访问
@
的效率的一般性讨论,请参阅:

对于您的特定代码,我将使用
shift
,但使用哈希片简化数据提取:

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

我假设这个方法对这些变量做了一些其他的事情,这使得将它们保存在单独的变量中是值得的(也许散列是只读的,在将它们插入到其他数据之前需要做一些修改?)--否则,为什么不把它们放在它们开始的hashref中呢?

我的规则是,在长度超过两个语句的子例程中,我尽量不使用
$\u0]
。然后,所有内容都会得到一个用户定义的变量


为什么要将所有散列值复制到变量中?只需将它们放在它们所属的散列中。这比您所考虑的优化要好得多。

我不会说“这是常见的做法”。这实际上是一场只针对Perl的圣战。my($one,$two)=((shift),(shift));或者my($one,$two)=@;?
$hr->{elem1
$$hr{elem1}
都是groovy。
$$hr->{elem1}
不起作用。每次使用shift时,我都试图打自己一巴掌。这是一个非常坏的习惯,我几乎从来都不想改变。好的,“澄清”时间:shift对于一个变量来说非常好。我的($a,$b,$c)=@u对于多个变量来说非常好。抱歉出现任何混淆。将项目放入变量的一个很好的原因是
严格的“vars”
提供的打字保护。使用
hash::Util::lock_keys
锁定哈希键也可以获得同样的好处。这根本不是我在函数中真正做的,我只是举个例子问题中的示例。@OP:好的,我就是这么想的。:(顺便说一句,你可以通过进入你的个人资料页给自己一个更好的用户名-)除了一个例外,我宁愿避免移动
@
,而是从中进行列表赋值——即使是一个参数,因为这意味着我不会意外地将
my$one=shift
转换为
my$one$two=shift
而引入bug。OO代码(特别是构造函数或委托或重新修补的函数)中的例外情况是,移位
$self
使事情变得更简单。我只在两种情况下使用
$\u0]
:类访问器(满足“语句对”规则)迈克尔·卡曼:如果你愿意,你可以避免使用
$[0]
,并像这样显式地记录你的就地修改:
perl-Mstrict-wle'sub-arg\u别名{\@}sub foo{my$arg\u别名=&arg\u别名;my($foo)=print“foo was$foo”;$arg\u别名->[0]=“plugh”}我的$foo=“xyzy”;$foo($foo);打印“foo现在是$foo”
@ysth,你就不能把refs带进
@
?类似于
sub foo{my$arg1=\$[0];$$arg1=~s/foo/bar/
这样就可以避免额外的函数调用。或者要得到整个数组,
my@arg refu=map}{@;