In Perl come si sceglie dinamicamente quale metodo utilizzare come callback?
Domanda
In Perl, è abbastanza banale specificare un callback o un riferimento al codice se il suo pacchetto è noto:
package Foo;
sub foo { print "in foo" }
# and then
package main;
sub baz {
my $code = shift;
$code->();
}
baz( \&Foo::foo );
E questo stampa in foo
.
Diciamo che hai un oggetto, ancora così banale, come questo:
package Foo;
sub new { bless {}, shift }
sub bar { print "in bar" }
sub baz { print "in baz" }
Puoi cercare il metodo usando il modo sopra (\ & amp; Package: Method) e chiamarlo come
package main;
my $foo = Foo->new();
my $ref = \&Foo::bar;
$foo->$ref();
Ma a volte (ok, spesso) non conosci il tipo esplicito. Diciamo che c'è Foo
, Bar
, Baz
e tutti hanno il loro metodo blat
. Vorresti ottenere il riferimento al metodo appropriato, basato sull'oggetto anziché sul pacchetto. Come lo faresti?
Soluzione
my $ref = $obj->can('blat');
Se $ ref non è definito, l'oggetto non può essere cancellato. Se $ ref non è indefinito, è un riferimento CODICE valido alla funzione in questione, adatto per chiamare " $ obj- > $ ref (@args) " ;.
Altri suggerimenti
Lascia che la ricerca del metodo faccia il lavoro per te:
$ 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
Se hai bisogno di un riferimento, tieni presente che Perl non ha delegati, ma puoi avvicinarti:
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";
}
Ancora più vicino sarebbe:
my $delegate = sub { $obj->$ref };
# or sub { $obj->$method }
print $delegate->(), "\n";