2009-06-24 12 views
1

En Perl, il est assez trivial de spécifier un rappel ou une référence code si son emballage est connu:En Perl comment choisissez-vous dynamiquement quelle méthode utiliser comme callback?

package Foo; 

sub foo { print "in foo" } 

# and then 
package main; 

sub baz { 
    my $code = shift; 
    $code->(); 
} 

baz(\&Foo::foo); 

Et ceci affiche in foo.

Disons que vous avez un objet, jamais si trivial, comme ceci:

package Foo; 

sub new { bless {}, shift } 
sub bar { print "in bar" } 
sub baz { print "in baz" } 

Vous pouvez consulter la méthode en utilisant la manière ci-dessus (\ & Package: méthode) et l'appeler comme

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 y a Foo, Bar, Baz, et ils ont tous leur propre méthode . Vous voudriez obtenir la référence à la méthode appropriée, basée sur l'objet au lieu du paquet. Comment allez-vous à ce sujet?

Répondre

7
my $ref = $obj->can('blat'); 

Si $ ref est undef, votre objet ne peut pas blatter. Si $ ref n'est pas undef, il s'agit d'une référence CODE valide à la fonction en question, appropriée pour appeler "$ obj -> $ ref (@args)".

+0

Parfait. Merci! –

3

Soit recherche de méthode faire le travail pour vous:

$ 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, gardez à l'esprit que Perl n'a pas les délégués, mais vous pouvez 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"; 
} 

serait encore plus proche:

my $delegate = sub { $obj->$ref }; 
#   or sub { $obj->$method } 
print $delegate->(), "\n"; 
+1

est peut-être la bonne façon de faire - mais la page UNIVERSAL perldoc dit explicitement NE PAS faire UNIVERSAL :: can() directement - cela fait que les remplacements ne fonctionnent pas. voir http://perldoc.perl.org/UNIVERSAL.html –

+0

Assez juste. Modifié. –