2009-06-24 7 views
1

In Perl, ist es ziemlich trivial einen Rückruf oder Referenz-Code angeben, wenn sein Paket bekannt ist:In Perl wie wählen Sie dynamisch, welche Methode als Callback verwendet werden soll?

package Foo; 

sub foo { print "in foo" } 

# and then 
package main; 

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

baz(\&Foo::foo); 

Und das druckt in foo.

Können sagen, Sie ein Objekt haben, noch so trivial, wie folgt aus:

package Foo; 

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

Sie können die Methode unter Verwendung der obigen Art und Weise nachschlagen (\ & Paket: Method) und nennen Sie es wie

package main; 
my $foo = Foo->new(); 
my $ref = \&Foo::bar; 
$foo->$ref(); 

Aber manchmal (okay, oft) kennen Sie den expliziten Typ nicht. Sagen wir es gibt Foo, Bar, Baz, und sie alle haben ihre eigene blat Methode. Sie möchten den Verweis auf die entsprechende Methode basierend auf dem Objekt anstelle des Pakets abrufen. Wie würdest du das machen?

Antwort

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

Wenn $ ref nicht undef ist, kann Ihr Objekt nicht blattern. Wenn $ ref nicht undef ist, handelt es sich um einen gültigen CODE-Verweis auf die fragliche Funktion, der zum Aufrufen von "$ obj -> $ ref (@args)" geeignet ist.

+0

Perfekt. Vielen Dank! –

3

Methode Let Lookup tun, um die Arbeit für Sie:

$ 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 

Wenn Sie eine Referenz benötigen, denken Sie daran, dass Perl nicht delegiert hat, aber Sie können in der Nähe erhalten:

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"; 
} 

noch näher wäre:

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

kann ist trotzig der richtige Weg zu gehen - aber die UNIVERSAL perldoc Seite sagt explizit NICHT UNIVERSAL :: kann() direkt - das macht es so Overrides nicht funktionieren. siehe http://perldoc.perl.org/UNIVERSAL.html –

+0

Fair genug. Überarbeitet. –