12
{
  sub a {
    print 1;
  }
}
a;

バグですか?

a外部からは利用できません。

Perl 6* で動作しますか?

※申し訳ありませんが、まだインストールしていません。

4

7 に答える 7

30

サブがブロックの外に見える理由を尋ねていますか? もしそうなら、それはコンパイル時のsubキーワードがサブを名前空間に置くためです(キーワードを使用して新しい名前空間を作成しmainない限り)。package次のようなものを試すことができます

{
  my $a = sub {
    print 1;
  };
  $a->(); # works
}
$a->(); # fails

この場合、subキーワードはサブルーチンを作成してmain名前空間に配置するのではなく、匿名サブルーチンを作成してレキシカル スコープの変数に格納します。変数がスコープ外になると、(通常は) 使用できなくなります。

詳細を読むには、チェックアウトしてくださいperldoc perlsub

また、Perl パーサーがコードを認識する方法を検査できることもご存知でしたか? のようにフラグ-MO=Deparseを付けて perl を実行しperl -MO=Deparse yourscript.plます。元のコードは次のように解析されます。

sub a {
    print 1;
}
{;};
a ;

サブルーチンが最初にコンパイルされ、次にブロックがコードなしで実行され、次にa呼び出されます。

Perl 6 での私の例については、「成功」、「失敗」を参照してください。Perl 6 では、逆参照は では.ないことに注意してください->

編集: Perl 5.18 で期待されるレキシカル サブルーチンの新しい実験的サポートに関する別の回答を追加しました。

于 2011-09-23T02:54:22.213 に答える
17

Perl 6では、潜水艦は確かに字句スコープであるため、コードはエラーをスローします(すでに数人が指摘しているように)。

これにはいくつかの興味深い意味があります。

  • ネストされた名前付き潜水艦は適切なクロージャとして機能します(perl 5の「共有されたままになりません」という警告も参照してください)。
  • モジュールからのサブのインポートは、字句スコープに機能します
  • 組み込み関数は、プログラムの外側の字句スコープ(「設定」)で提供されるため、同じ名前の関数を宣言またはインポートするのと同じくらい簡単にオーバーライドできます。
  • lexpadは実行時に不変であるため、コンパイラーはコンパイル時に不明なルーチンへの呼び出しを検出できます(nieczaはすでにそれを行っており、Rakudoは「オプティマイザー」ブランチでのみ検出します)。
于 2011-09-23T06:19:18.643 に答える
14

サブルーチンは、ブロック スコープではなく、パッケージ スコープです。

#!/usr/bin/perl
use strict;
use warnings;

package A;
sub a {
    print 1, "\n";
}
a();
1;

package B;
sub a {
    print 2, "\n";
}
a();
1;
于 2011-09-23T03:02:10.597 に答える
13

Perlの名前付きサブルーチンは、グローバル名として作成されます。他の回答は、匿名のサブルーチンを字句変数に割り当てることによって字句サブルーチンを作成する方法を示しています。もう1つのオプションは、local変数を使用して動的スコープのサブを作成することです。

2つの主な違いは、呼び出しスタイルと可視性です。動的スコープのサブは、名前付きサブのように呼び出すことができ、定義されているブロックがなくなるまでグローバルに表示されます。

use strict;
use warnings;
sub test_sub {
    print "in test_sub\n";
    temp_sub();
}

{
    local *temp_sub = sub {
        print "in temp_sub\n";
    };
    temp_sub();
    test_sub();
}
test_sub();

これは印刷する必要があります

in temp_sub
in test_sub
in temp_sub
in test_sub
Undefined subroutine &main::temp_sub called at ...
于 2011-09-23T20:10:13.243 に答える
8

@tchristによる別の叱責の危険を冒して、私は完全性のために別の答えを追加しています。まだリリースされていないPerl5.18には、実験的な機能として字句サブルーチンが含まれていると予想されます。

関連するドキュメントへのリンクは次のとおりです。繰り返しになりますが、これは非常に実験的なものであり、次の2つの理由から本番コードには使用しないでください。

  1. まだうまく実装されていない可能性があります
  2. 予告なく削除される場合があります

だから、あなたが望むなら、この新しいおもちゃで遊んでください、しかしあなたは警告されました!

于 2012-10-12T20:51:51.053 に答える
7

コードがコンパイルされ、実行され、「1」が表示される場合、バグは発生していません。

サブルーチンは、それらが定義されている字句スコープ内でのみ呼び出し可能であると期待しているようです。それは、他のファイルで定義されたサブルーチンを呼び出すことができないことを意味するため、悪いことです。おそらく、各ファイルが独自のレキシカル スコープで評価されることに気付いていないでしょうか? それは好きなものを可能にします

my $x = ...;
sub f { $x }
于 2011-09-23T03:32:11.190 に答える
6

はい、これは設計上の欠陥だと思います。具体的には、Perl で作成された字句スコープではなく動的スコープを使用するという最初の選択が、自然にこの動作につながります。しかし、すべての言語設計者とユーザーが同意するわけではありません。したがって、あなたが尋ねる質問には明確な答えがありません。

レキシカル スコープは Perl 5 で追加されましたが、オプション機能として、常に具体的に示す必要があります。その設計上の選択には完全に同意します。下位互換性は重要です。

于 2011-09-26T13:04:40.383 に答える