一部のユーザーがPerlでクラス名を引用するのはなぜですか?


12

を見るとType::Tiny、の呼び出しのクラス名がType::Tiny->new公式ドキュメントに引用されていることがわかります。

my $NUM = "Type::Tiny"->new(
   name       => "Number",
   constraint => sub { looks_like_number($_) },
   message    => sub { "$_ ain't a number" },
);

どうしてこれなの?これは単なるスタイルですか?このプラクティスにはパフォーマンス上の影響がありますか?

回答:


7

より簡単な例をとる

package Foo { sub new { die 7  } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();

上記の例では、定数Fooは「Bar」に解決されるため、これは"Bar"->newnotを呼び出します"Foo"->new。サブルーチンの解決をどのように停止しますか?あなたはそれを引用することができます。

"Foo"->new();

パフォーマンスへの影響に関しては、ベアワードではなく文字列を使用しても、状況は悪化しません。によって生成されたoptree O=Deparseが同じであることを確認しました。したがって、原則として、正確さを重視する場合はクラス名を引用する方がよいようです。

これはプログラミングPerlで言及されています(悲しいことに、間接的なメソッド呼び出しのコンテキストで)

...したがって、2つの条件が満たされていれば、ほとんどの場合、ベアクラス名で問題を回避できることをお伝えします。まず、クラスと同じ名前のサブルーチンはありません。(あなたがいることを慣例に従っている場合のように、サブルーチンの名前newのようなスタート小文字名とクラス名ElvenRing開始大文字、これが問題になることはありません)。第二に、クラスはのいずれかでロードされました

use ElvenRing;
require ElvenRing;

これらの宣言のいずれかにより、PerlがElvenRingモジュール名であることを確実に認識できます。これにより、たとえ現在のパッケージで独自のサブルーチンを宣言した場合でもnew、クラス名の前のようなすべての裸の名前ElvenRingがメソッド呼び出しとして解釈されnewます。

そして、それは理にかなっています:ここでの混乱は、サブルーチン(通常は小文字)がクラスと同じ名前(通常は大文字)を持っている場合にのみ発生します。これは、上記の命名規則に違反した場合にのみ発生します。

tldr; クラス名を知っていて、乱雑さよりも正確さを重視する場合は、クラス名を引用することをお勧めします。

補足:::上記の例のように、関数の最後にa を付けることで、関数へのベアワードの解決を停止することもできますFoo::->new


これを指摘してくれたredditのGinnz と、コメントを寄せてくれToby Inksterに感謝します(ただし、最初に読んだときには意味がありませんでした)。


2
あるいはFoo::->new、池上から学んだように。
mob

@mobええ、Perlの本ではそれも(明示的に)言及されています。笑。
エヴァンキャロル

@mob私も脚注として追加しました。好きかどうかはわかりませんが。
エヴァンキャロル

1
Foo::Foo既存のパッケージでない場合に警告するという利点があります
池上

1
Try :: TinyはFooよりも良い例です。使用するコードFoo->では、パッケージにそのようなサブルーチンがないことを知っていることが期待できます。しかし、Try :: Tinyと他の多数のcpan /その他の外部ソースモジュールを使用している場合、それらの1つがTryパッケージを使用しているかどうか、そして使用している場合は、Tinyサブがそこにあるかどうかを確認します。
yth、

0

ベアワード(文字列として扱われる)を使用するのではなく、クラス名を明示的に引用することは、構文のあいまいさを回避する3つの方法の1つです。perlobjドキュメンテーション「クラスメソッド呼び出しセクションで説明しています。

Perlではパッケージ名とサブルーチン名にベアワードを使用できるため、ベアワードの意味が誤って解釈されることがあります。例えば、構築物は、Class->new()いずれかのように解釈することができます'Class'->new()Class()->new().IN英語、第二の解釈として読み込むこと「という名前のサブルーチンを呼び出すClass()場合、呼び出しnew()の戻り値のメソッドとしてClass()。」Class()現在の名前空間で指定されたサブルーチンがある場合、Perlは常にClass->new()2番目の代替として解釈します:への呼び出し new()によって返されたオブジェクトに対するへの呼び出しClass()

以下のデモで、この奇妙なケースの動作をご覧ください。

#! /usr/bin/env perl

use strict;
use warnings;

sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }

sub Type::Tiny::new { print "Type::Tiny::new\n" }

sub Bogus::new { print "Bogus::new\n" }

my $class = "Type::Tiny";

Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;

その出力は

偽物を返す
偽:: new
タイプ:: Tiny :: new
タイプ:: Tiny :: new
タイプ:: Tiny :: new

前述のドキュメントセクションの残りの部分では、予期しない動作や不注意によるエラーから保護する方法を示します。

2つの方法で、Perlに最初の解釈を(つまり、というクラスのメソッド呼び出しとして)使用するように強制でき"Class"ます。まず、::クラス名にa を追加できます。

Class::->new()

Perlは常にこれをメソッド呼び出しとして解釈します。

または、クラス名を引用することもできます。

'Class'->new()

もちろん、クラス名がスカラーにある場合、Perlは正しいことも行います。

my $class = 'Class';
$class->new();

あなたの質問に適用すると、以下のすべての呼び出しは同等です。

Type::Tiny::->new(  );

"Type::Tiny"->new(  );

my $class = "Type::Tiny";
$class->new(  );

::最後に追加すると、役立つ警告が表示されるという利点があります。誤って入力したとしましょう

Type::Tinny::->new;

それが生み出す

ベアワード "Type :: Tinny ::"は、。/ try行15に存在しないパッケージを参照しています。
./try行15で、パッケージ "Type :: Tinny"を介してオブジェクトメソッド "new"を見つけることができません( "Type :: Tinny"の読み込みを忘れた可能性があります)。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.