15

与えられたサブルーチンの位置パラメータを 3 つまでにするという Damian Conway のベスト プラクティスをしばらく無視してみましょう。

パフォーマンスまたは機能に関して、以下の 2 つの例に違いはありますか?

使用shift:

sub do_something_fantastical {
    my $foo   = shift;
    my $bar   = shift;
    my $baz   = shift;
    my $qux   = shift;
    my $quux  = shift;
    my $corge = shift;
}

使用@_:

sub do_something_fantastical {
    my ($foo, $bar, $baz, $qux, $quux, $corge) = @_;
}

両方の例がパフォーマンスと機能の点で同じである場合、人々は一方の形式を他方の形式よりもどう考えているでしょうか? @_使用例の方がコードの行数が少ないのは明らかshiftですが、他の例で示したように使用する方が読みやすいのではないでしょうか? 正当な理由のある意見は大歓迎です。

4

9 に答える 9

28

機能的な違いがあります。シフトは変更します@_が、からの割り当ては変更し@_ません。後で使用する必要がない場合は@_、その違いはおそらく問題ではありません。私は常にリスト割り当てを使用しようとしますが、時々使用しますshift

ただし、で始める場合はshift、次のようになります。

 my( $param ) = shift;

私はよくこのバグを作成します:

 my( $param, $other_param ) = shift;

それは私があまり使用しないためです。shiftそのため、割り当ての右側に移動して、それをに変更するのを忘れてい@_ます。これが、を使用しない場合のベストプラクティスのポイントですshiftshiftあなたの例のように、それぞれに別々の行を作成することもできますが、それは面倒です。

于 2009-01-06T06:54:26.063 に答える
16

少なくとも私のシステムでは、Perlのバージョンとアーキテクチャに依存しているようです。

#!/usr/bin/perl -w
use strict;
use warnings;
use autodie;

use Benchmark qw( cmpthese );

print "Using Perl $] under $^O\n\n";

cmpthese(
    -1,
    {
        shifted   => 'call( \&shifted )',
        list_copy => 'call( \&list_copy )',
    }
);

sub call {
    $_[0]->(1..6);  # Call our sub with six dummy args.
}

sub shifted {
    my $foo   = shift;
    my $bar   = shift;
    my $baz   = shift;
    my $qux   = shift;
    my $quux  = shift;
    my $corge = shift;

    return;
}

sub list_copy {
    my ($foo, $bar, $baz, $qux, $quux, $corge) = @_;
    return;
}

結果:

Using Perl 5.008008 under cygwin

              Rate   shifted list_copy
shifted   492062/s        --      -10%
list_copy 547589/s       11%        --


Using Perl 5.010000 under MSWin32

              Rate list_copy   shifted
list_copy 416767/s        --       -5%
shifted   436906/s        5%        --


Using Perl 5.008008 under MSWin32

              Rate   shifted list_copy
shifted   456435/s        --      -19%
list_copy 563106/s       23%        --

Using Perl 5.008008 under linux

              Rate   shifted list_copy
shifted   330830/s        --      -17%
list_copy 398222/s       20%        --

したがって、実際にはシフトがわずかに速いPerl 5.10を除いて、list_copyはシフトよりも通常20%高速であるように見えます。

これらはすぐに導き出された結果であることに注意してください。ベンチマークは、サブルーチンの呼び出しと戻りにかかる時間もカウントするため、実際の速度の差はここにリストされているものよりも大きくなります。これは、結果に適度な影響を及ぼします。Perlが特別な種類の最適化を行っているかどうかを確認するための調査は行っていません。あなたのマイレージは異なる場合があります。

ポール

于 2009-01-06T05:50:39.093 に答える
8

shift の例は @_ を使用するよりも遅いと思います。関数呼び出しが 1 回ではなく 6 回であるためです。それぞれを 10,000 回の反復のループに入れ、時間を計ります。

美学に関しては、@_ メソッドを好みます。shift メソッドを使用すると、誤ってカット アンド ペーストして変数の順序を台無しにするのは簡単すぎるようです。また、多くの人が次のようなことをしているのを見てきました。

sub do_something {
   my $foo = shift;
   $foo .= ".1";

   my $baz = shift;
   $baz .= ".bak";

   my $bar = shift;
   $bar .= ".a";
}

これは、私見ですが、非常に厄介で、簡単にエラーにつながる可能性があります。たとえば、baz ブロックを切り取って、bar ブロックの下に貼り付けた場合などです。私はすべて、変数が使用される場所の近くで変数を定義することに賛成ですが、渡された変数を関数の先頭で定義することが優先されると思います。

于 2009-01-06T03:50:30.163 に答える
4

通常、私は最初のバージョンを使用します。これは、通常、シフトと一緒にエラー チェックを行う必要があるためです。このほうが書きやすいからです。言う、

sub do_something_fantastical {
    my $foo   = shift || die("must have foo");
    my $bar   = shift || 0;  # $bar is optional
    # ...
}
于 2009-01-06T03:57:00.603 に答える
3

@_ をリストとしてアンパックすることを好みます (2 番目の例)。ただし、Perl のすべてと同様に、shift を使用すると便利な場合があります。たとえば、基本クラスでオーバーライドされることを意図しているが、オーバーライドされていない場合でも機能することを確認したいパススルー メソッドなどです。


package My::Base;
use Moose;
sub override_me { shift; return @_; }

于 2009-01-06T04:23:59.300 に答える
1

最良の方法は、私見ですが、モジュール内の新しい関数のように、2 つをわずかに混合することです。

our $Class;    
sub new {
    my $Class = shift;
    my %opts = @_;
    my $self = \%opts;
    # validate %opts for correctness
    ...
    bless $self, $Class;
}

次に、コンストラクターへのすべての呼び出し引数がハッシュとして渡されます。これにより、コードは単なるパラメーターのリストよりもはるかに読みやすくなります。

さらに、ブライアンが言ったように、@_変数は変更されていないため、異常な場合に役立ちます。

于 2009-07-21T03:42:05.387 に答える
0

あなたが(大まかに)同等のことをしているなら、私は疑っています:

push @bar, shift @_ for (1 :: $big_number);

それからあなたは何か間違ったことをしています。私my ($foo, $bar) = @_;はほとんどの場合、後者を数回使用して足を撃ったので、フォームを使用します...

于 2009-02-18T10:53:17.613 に答える
0

私は好む

sub factorial{
  my($n) = @_;

  ...

}

Komodo を使用すると、引数が何であるかを教えてくれるという単純な理由からです。

于 2009-07-21T03:07:12.240 に答える