Der ${...}
ist der Skalar-Dereferenzierungsoperator, nicht der anonyme Subroutinenkonstruktor. Sie wollen:
my $coderef = sub {MyModule::MyTool->new};
Und wenn Ihr Konstruktorargumente nimmt, könnte man es auf diese Weise schreiben:
my $coderef = sub {MyModule::MyTool->new(@_)};
Die beiden oben genannten Beispiele nicht ein Problem beheben, und dass die Funktionalität von caller
wird erhalten. Wenn Ihr Konstruktor dies muss (viele nicht), können Sie Perl Magie goto &sub
Syntax:
my $coderef = sub {unshift @_, 'MyModule::MyTool'; goto &{$_[0]->can('new')} };
, die wahrscheinlich eine kleine Erklärung erfordert. Zuerst wird der Modulname vor allen anderen Argumenten platziert (was die Methode new
erwartet). Dann habe ich die UNIVERSAL
Methode ->can
verwendet, um die Coderef für die new
Methode abzurufen. goto &{...}
springt dann mit der aktuellen Argumentliste zu dieser Codeferenz.
EDIT: Die folgenden Kommentare zeigen, dass es einige Verwirrung gibt, wenn Sie die längere dritte Technik verwenden müssten. Hier ist ein kurzes Segment, das das Problem zeigt:
package Original;
sub new {say +(caller)[0]} # presumably some better use of caller
# or Carp (which uses caller)
package Encapsulate::Simple;
sub new {
my (undef, $invocant, $method) = @_;
sub {$invocant->$method(@_)}
}
package Encapsulate::Better;
sub new {
my (undef, $invocant, $method) = @_;
sub {unshift @_, $invocant; goto &{$invocant->can($method)}}
}
package main;
my $bad = Encapsulate::Simple->new(qw/Original new/);
$bad->(); # always prints 'Encapsulate::Simple'
my $good = Encapsulate::Better->new(qw/Original new/);
$good->(); # prints 'main' as it should
package another;
$bad->(); # erroneously prints 'Encapsulate::Simple' again
$good->(); # prints 'another' as it should
Also kurz gesagt, Encapsulate::Better
‚s Unter bewahrt die genauen Funktionalität von Original->new
während Encapsulate::Simple
dauerhaft bindet es an die Verpackung, keine gekapselten Methoden zu brechen, die caller
für alles verwenden.
Aber ich möchte diesen Konstruktor nicht aufrufen. Ich brauche nur einen Hinweis darauf zu bekommen. Ich möchte ein Array von Codereferenzen für einige Konstruktoren erstellen, um sie später aufzurufen. – jesper
@jesper, der anonyme Sub ruft den Konstruktor nicht auf, bis er mit '$ codeRef ->() ausgeführt wird;' – friedo
Hmm, also muss ich mir meinen Code etwas genauer ansehen. ;) – jesper