En Perl, comment choisissez-vous dynamiquement la méthode à utiliser comme rappel?
Question
En Perl, il est assez simple de spécifier un rappel ou une référence de code si son package est connu:
package Foo;
sub foo { print "in foo" }
# and then
package main;
sub baz {
my $code = shift;
$code->();
}
baz( \&Foo::foo );
Et cela affiche dans foo
.
Disons que vous avez un objet très trivial, comme ceci:
package Foo;
sub new { bless {}, shift }
sub bar { print "in bar" }
sub baz { print "in baz" }
Vous pouvez rechercher la méthode en utilisant la méthode ci-dessus (\ & amp; Package: Method) et l'appeler comme suit
package main;
my $foo = Foo->new();
my $ref = \&Foo::bar;
$foo->$ref();
Mais parfois (d'accord, souvent) vous ne connaissez pas le type explicite. Disons qu'il existe Foo
, Bar
, Baz
et qu'ils ont tous leur propre méthode blat
. Vous voudriez obtenir la référence à la méthode appropriée, basée sur l'objet plutôt que sur le package. Comment vous y prendriez-vous?
La solution
my $ref = $obj->can('blat');
Si $ ref est undef, votre objet ne peut pas blater. Si $ ref n’est pas undef, il s’agit d’une référence CODE valide à la fonction en question, qui convient à l’appel " $ obj- > $ ref (@args) ".
.Autres conseils
Laissez la recherche de méthode faire le travail à votre place:
$ cat try
#! /usr/bin/perl
use warnings;
use strict;
package Foo;
sub new { bless {} => shift }
sub blat { "Foo blat" }
package Bar;
sub new { bless {} => shift }
sub blat { "Bar blat" }
package Baz;
sub new { bless {} => shift }
sub blat { "Baz blat" }
package main;
my $method = "blat";
foreach my $obj (Foo->new, Bar->new, Baz->new) {
print $obj->$method, "\n";
}
$ ./try
Foo blat
Bar blat
Baz blat
Si vous avez besoin d'une référence, n'oubliez pas que Perl n'a pas de délégué, mais vous pouvez vous en approcher:
my @objs = (Foo->new, Bar->new, Baz->new);
my $method = "blat";
my $obj = $objs[rand @objs];
my $ref = $obj->can($method);
if ($ref) {
print $ref->($obj), "\n";
}
else {
print "$obj: no can $method\n";
}
Encore plus proche serait:
my $delegate = sub { $obj->$ref };
# or sub { $obj->$method }
print $delegate->(), "\n";