8

次のスニペットがまったく機能しないのはなぜですか?そして、これを使用してどのような悪が可能でしょうか?しかし、真剣に、何らかの理由がありますか?のコードは${}まったく評価されてから、スカラー参照として使用されますか?

use strict;
no strict 'refs';

our $message = "Hello world!";
print "${ lc 'MESSAGE' }\n";
4

3 に答える 3

13

これについては、中級Perlで詳しく説明します。

変数ルックアップの一般的な構文は次のとおりです。

 SIGIL  BLOCK  INDEXY-THING

次のような単純なスカラーの場合:

 print $   { foo };

変数名をそれを取り巻くものから分離する必要があるときに、おそらくこれを見たことがあるでしょう。

 print "abc${foo}def\n";

ブロックにPerl識別子があり、周囲に混乱がない場合は、中かっこを省略できます。これは一般的なケースです。

 print $foo;

ただし、これは参照を逆参照する場合と同じです。

 SIGIL  BLOCK-RETURNING-REFERENCE  INDEXY-THINGS

ブロックで取得したものが参照である場合、Perlはあなたが要求したようにそれを逆参照しようとします。

 my $ref = \ '12345';
 print $     { $ref };

それは本当のブロックですが、砂糖だけではありません。そこには、好きなだけステートメントを含めることができます。

 print $     { my $ref = \ '1234'; $ref };

これで、Perl識別子を指定するだけではないため、Perlは識別子を指定しているとは想定せず、コードを実行して結果を参照として使用します。sayこれらのほぼ同一のステートメントの違いを考慮してください。

    use 5.010;
our $foo = "I'm the scalar";

sub foo { \ "I'm the sub" }

say ${foo};
say ${foo;};

その2番目sayのPerlはセミコロンを認識し、それが識別子ではないことを認識し、中括弧内のコードをテキストとして解釈し、結果を返します。結果は参照であるため、を使用し${...}て逆参照します。これをどこで行うかは問題ではないので、二重引用符で囲まれた文字列内で行うのは特別なことではありません。

また、ourそこに注意してください。もう少しトリッキーなことを検討するので、これは重要です。

    use 5.010;
our $foo = "I'm the scalar";

sub foo { \ "I'm the sub" }
sub baz { 'foo' }

say ${foo};
say ${foo;};
say ${baz;};

Perlはそれsayをコードとして解釈し、結果が参照ではないことを確認します。単純な文字列fooです。Perlは、それが参照ではないことを認識しますが、現在は逆参照コンテキストにあるため、シンボリック参照を実行します(Greg Baconが説明しているように)。シンボリック参照はシンボルテーブル内の変数で機能する$fooため、パッケージ変数である必要がありました。

これを台無しにするのは簡単なので、それをstrictチェックするのに便利です。ただし、オフにした場合でも、噛まれても驚かないでください。:)

于 2010-02-25T23:09:31.077 に答える
5

perlrefドキュメントの「参照の使用」セクションから:

変数名またはサブルーチン名の一部として識別子(または識別子のチェーン)を配置する場合はいつでも、識別子を正しいタイプの参照を返すBLOCKに置き換えることができます。言い換えると、前の例は次のように書くことができます。

$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
$globref->print("output\n");  # iff IO::Handle is loaded

確かに、この場合にカーリーを使用するのは少しばかげていますが、BLOCKには任意の式、特に添え字付きの式を含めることができます。

&{ $dispatch{$index} }(1,2,3);    # call correct routine

の単純な場合のカーリーを省略できるため$$x、間接参照記号を適切な演算子と見なすのを間違え、優先順位について疑問に思うことがよくあります。ただし、中括弧の代わりに括弧を使用することもできます。そうではありません。以下の違いを考慮してください。ケース0は、ケース2ではなくケース1の短縮版です。

$$hashref{"KEY"}   = "VALUE";     # CASE 0
${$hashref}{"KEY"} = "VALUE";     # CASE 1
${$hashref{"KEY"}} = "VALUE";     # CASE 2
${$hashref->{"KEY"}} = "VALUE";   # CASE 3

ケース2は、おそらく参照しているハッシュを%hashref逆参照するのではなく、と呼ばれる変数にアクセスしているという点でも欺瞞的です。$hashrefそれはケース3になります。

後の「シンボリックリファレンス」:

参照は、定義されていない場合は必要に応じて発生すると述べましたが、参照として使用される値がすでに定義されている場合はどうなるかについては述べていませんが、ハードリファレンスではありません。参照として使用する場合は、シンボリック参照として扱われます。つまり、スカラーの値は、(おそらく)匿名の値への直接リンクではなく、変数の名前と見なされます。

于 2010-02-25T11:39:02.440 に答える
4

シンボリック参照を使用しない限り、問題ありません。次のコードを想定します。

my %messages = (hello => "Hello world!", bye => "Bye-bye, world!");
sub get_message_ref { return \$messages{$_[0]} }; # returns scalarref
print "${ get_message_ref('bye') }\n";

同意します。その有用性はscalarrefsでは明らかではありませんが、arrayrefsでは非常に有用です。

print "keys: @{[keys %messages]}\n";
于 2010-02-25T09:29:37.300 に答える