27

何年も前に、私はこれをカウンセリングしている仲間のプログラマーを覚えています:

new Some::Class;    # bad! (but why?)

Some::Class->new(); # good!

悲しいことに、私はその理由を思い出せません。:(コンストラクタがSome::Classモジュールに実際に存在していなくても、どちらの形式も正しく機能しますが、代わりにどこかの親から継承されます。

これらの形式はどちらもSome::Class :: new()と同じではありません。これは、クラスの名前を最初のパラメーターとしてコンストラクターに渡さないため、この形式は常に正しくありません。

2つの形式が同等であっても、Some :: Class-> new()は、モジュールでメソッドを呼び出すための標準的な規則に従っているため、はるかに明確であることがわかります。perlでは、「new」メソッドはそうではありません。特別-コンストラクターは何でも呼び出すことができ、new()は何でも行うことができます(もちろん、私たちは一般的にコンストラクターであると期待していますが)。

4

4 に答える 4

26

を使用するnew Some::Classことは「間接的な」メソッド呼び出しと呼ばれ、構文にあいまいさが生じるため良くありません。

失敗する理由の 1 つは、オブジェクトの配列またはハッシュがある場合です。あなたは期待するかもしれません

dosomethingwith $hashref->{obj}

に等しくなる

$hashref->{obj}->dosomethingwith();

しかし、実際には次のように解析されます。

$hashref->dosomethingwith->{obj}

これはおそらくあなたが望んでいたものではありません。

もう 1 つの問題は、呼び出しようとしているメソッドと同じ名前の関数がパッケージ内にある場合です。たとえばuse、関数をエクスポートしたモジュールが という名前の場合はどうなるdosomethingwithでしょうか。その場合、dosomethingwith $objectはあいまいであり、不可解なバグが発生する可能性があります。

構文を排他的に使用する->と、これらの問題が解消されます。これは、メソッドと、メソッドで操作する対象が常にコンパイラに対して明確であるためです。

于 2009-01-09T21:23:58.157 に答える
21

その落とし穴の説明については、perlobjドキュメントの間接オブジェクト構文を参照してください。freidoの答えはそれらの1つをカバーしています(ただし、関数呼び出しの周りに明示的な親を使用することでそれを避ける傾向があります)。

Larryはかつて、C ++を満足させるためにそこにあると冗談を言っていましたnew。人々はそれを絶対に使用しないように言うでしょうが、おそらくあなたはいつもそれをやっています。このことを考慮:

print FH "Some message";

ファイルハンドルの後にコンマがないのではないかと思ったことはありませんか?そして、間接オブジェクト表記のクラス名の後にコンマはありませんか?それがここで起こっていることです。これをprintのメソッド呼び出しとして書き直すことができます。

FH->print( "Some message" );

あなたがそれを間違えた場合、あなたはいくつかの奇妙なことを経験したかもしれprintません。明示的なファイルハンドルの後にコンマを置くと、引数になります。

print FH, "some message";     # GLOB(0xDEADBEEF)some message

悲しいことに、Perlにはこの間抜けがあります。構文に含まれるすべてが最良のアイデアであるとは限りませんが、インスピレーションを得るために非常に多くのソースから取得すると、それが起こります。いくつかのアイデアは悪いものでなければなりません。

于 2009-01-09T20:49:16.370 に答える
4

間接オブジェクト構文は正当な理由で嫌われていますが、それはコンストラクターとは何の関係もありません。呼び出し元のパッケージに new() 関数が含まれることはほとんどありません。むしろ、他の 2 つの (より良い?) 理由で Package->new() を使用する必要があります。

  1. あなたが言ったように、他のすべてのクラス メソッドは Package->method() の形式を取るため、一貫性は良いことです

  2. コンストラクターに引数を提供している場合、またはコンストラクターの結果を取得してすぐにメソッドを呼び出している場合 (たとえば、オブジェクトを維持することを気にしない場合) は、次のように言う方が簡単です。

$foo = Foo->new(type => 'bar', style => 'baz');
Bar->new->do_stuff;

よりも

$foo = new Foo(type => 'bar', style => 'baz');
(new Bar)->do_stuff;
于 2009-01-10T00:51:06.130 に答える
-3

別の問題はnew Some::Class、実行時に発生することです。エラーがあり、テストでこのステートメントに分岐しない場合は、本番環境で発生するまでわかりません。Some::Class->new動的プログラミングを行っていない場合は、使用することをお勧めします。

于 2009-01-10T20:24:35.060 に答える