web-dev-qa-db-ja.com

&を使用してPerlサブルーチンを呼び出す必要があるのはいつですか?

私は人々が&を使用してPerlのサブルーチンを呼び出すべきではないことを聞きました。

function($a,$b,...);
# opposed to
&function($a,$b,...);

引数リストがオプションになることはわかっていますが、&を使用することが適切な場合と、絶対に使用しないほうがよい場合とはどのような場合ですか?

また、&を省略した場合、ここでパフォーマンスの向上がどのように発揮されますか?

47
user105033

IMO、_&_を使用する理由が唯一あるのは、次のようなコードリファレンスを取得または呼び出す場合です。

_sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();
_

ほとんどの状況でcanを使用する絶対にすべきではないを使用する主な時間は、デフォルト以外の呼び出し動作を指定するプロトタイプを持つサブルーチンを呼び出すときです。つまり、一部のプロトタイプでは、引数リストを再解釈できます。たとえば、_@array_および_%hash_仕様を参照に変換します。したがって、潜水艦はそれらの再解釈が発生したことを期待し、手で模倣するために必要な長さに移動しない限り、潜水艦は期待したものとは大きく異なる入力を取得します。

私は主に人々があなたがまだPerl 4スタイルで書いていることを伝えようとしていると思います、そして今私たちはPerl 5と呼ばれるはるかにきれいでより良いものを持っています。

パフォーマンスに関しては、Perlが_&_を無効にするサブ呼び出しを最適化するさまざまな方法があり、主なものの1つは定数のインライン化です。

また、_&_を使用すると、foo(@_)を使用してサブ呼び出しを転送する場合に、パフォーマンス上の利点が得られます。 _&foo_の使用は、foo(@_)よりも非常に高速です。プロファイリングでそのミクロ最適化が必要であることを明確に見つけない限り、私はそれをお勧めしません。

36
chaos

私は&を頻繁に乱用していますが、主に私が奇妙なインターフェースを使用しているためです。これらの状況のいずれかが必要ない場合は、&を使用しないでください。これらのほとんどは、サブルーチンを呼び出すのではなく、サブルーチン定義にアクセスするためのものです。それはすべて perlsub にあります。

  1. 名前付きサブルーチンへの参照を取得します。これは、ほとんどのPerlerでおそらく唯一の一般的な状況です。

     my $sub = \&foo;
    
  2. 同様に、typeglobに割り当てると、別の名前でサブルーチンを呼び出すことができます。

     *bar = \&foo;
    
  3. テストスイートの場合と同様に、サブルーチンが定義されていることを確認します。

     if( defined &foo ) { ... }
    
  4. 一般的ではないサブルーチン定義の削除:

     undef &foo;
    
  5. 呼び出す適切なサブルーチンを選択することが唯一の仕事であるディスパッチャサブルーチンを提供します。これが私が&を使用してサブルーチンをcall呼び出す唯一の状況であり、ディスパッチャを何度も呼び出すことを期待していて、操作から少しパフォーマンスを絞り込みます。

     sub figure_it_out_for_me {
        # all of these re-use the current @_
          if( ...some condition... ) { &foo     } 
       elsif( ...some other...     ) { &bar     }
       else                          { &default }
       }
    
  6. 現在の引数スタックを使用して別のサブルーチンにジャンプするには(およびコールスタック内の現在のサブルーチンを置き換える)、特にAUTOLOADでのディスパッチのレアな操作:

     goto ⊂
    
  7. Perlの組み込みにちなんで命名したサブルーチンを呼び出します。 &は常にユーザー定義のものを提供します。それは 私たちがそれを教える理由 Perlの学習 。通常はそうしたくないのですが、これは&の機能の1つです。

それらを使用できる場所はいくつかありますが、より良い方法があります。

  1. Perl組み込みと同じ名前のサブルーチンを呼び出す。組み込みのPerlと同じ名前のサブルーチンはありません。 perlfunc をチェックして、使用してはならない組み込み名のリストを確認します。

  2. プロトタイプを無効にします。それが何を意味するのか、またはなぜそれが必要なのかがわからない場合は、&を使用しないでください。いくつかの黒魔術コードはそれを必要とするかもしれませんが、それらの場合、おそらくあなたは何をしているのか知っています。

  3. サブルーチン参照を逆参照して実行します。 ->表記を使用してください。

52
brian d foy

&subroutine()フォームはプロトタイプチェックを無効にします。これは必要な場合とそうでない場合があります。

http://www.Perl.com/doc/manual/html/pod/perlsub.html#Prototypes

プロトタイプを使用すると、サブルーチン引数の数とタイプを指定し、コンパイル時にそれらをチェックすることができます。これは、有用な診断支援を提供できます。

プロトタイプは、メソッド呼び出し、または&接頭辞を使用して昔ながらのスタイルで行われた呼び出しには適用されません。

&は、サブルーチンまたはコード参照を参照または逆参照するために必要です

例えば.

sub foo {
   # a subroutine
}

my $subref = \&foo; # take a reference to the subroutine

&$subref(@args);  # make a subroutine call using the reference.

my $anon_func = sub { ... }; # anonymous code reference
&$anon_func(); # called like this

プロタイプは、サブルーチン参照にも適用できません。

&subroutineフォームは、いわゆる magic goto フォームでも使用されます。

表現 goto &subroutineは、@ _の現在の値を使用して、現在の呼び出しコンテキストを指定されたサブルーチンの呼び出しに置き換えます。

本質的に、名前付きの呼び出しを使用して、1つのサブルーチンへの呼び出しを完全に切り替えることができます。これは一般にAUTOLOADブロックで見られます。ここで、おそらく@_にいくつかの変更を加えて、遅延サブルーチン呼び出しを行うことができますが、プログラムからは名前付きサブルーチンへの呼び出しであるかのように見えます。

例えば.

sub AUTOLOAD {
    ...
    Push @_, @extra_args; # add more arguments onto the parameter list
    goto &subroutine ; # change call another subroutine, as if we were never here
}

}

これは 末尾呼び出しの排除 に役立つ可能性があると思います。

参照 このテクニックの詳細な説明はこちら

18
cms

私は「&」の使用に対する反対意見を読みましたが、ほとんどいつもそれを使用しています。それは私が時間を節約しすぎないようにします。コードのどの部分が特定の関数を呼び出すかを探すために、Perlコーディング時間の大部分を費やしています。先頭に&があれば、すぐに検索して見つけることができます。先頭に&がなければ、関数の定義、コメント、およびデバッグステートメントを取得します。通常、探しているコードを調べるために検査する必要があるコードの量が3倍になります。

「&」を使用しない主なことは、関数プロトタイプを使用できることです。ただし、Perl関数プロトタイプは、引数リストを受け取り、予期しない方法で再解釈するため、エラーを回避するのと同じくらい頻繁にエラーを作成する可能性があります。これにより、関数呼び出しは、文字通り、引数を渡さなくなります。

1
Phil Goetz