简体   繁体   中英

In Perl how do you dynamically pick what method to use as a callback?

In Perl, it's pretty trivial to specify a callback or code reference if its package is known:

package Foo;

sub foo { print "in foo" }

# and then
package main;

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

baz( \&Foo::foo );

And this prints in foo .

Lets say you have an object, ever so trivial, like this:

package Foo;

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

You can look up the method using the above way (\\&Package:Method) and call it like

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

But sometimes (okay, often) you don't know the explicit type. Lets say there's Foo , Bar , Baz , and they all have their own blat method. You'd want to get the reference to the appropriate method, based on the object instead of the package. How would you go about that?

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

If $ref is undef, your object can't blat. If $ref is not undef, it's a valid CODE reference to the function in question, suitable for calling "$obj->$ref(@args)".

Let method lookup do the work for you:

$ 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

If you need a reference, keep in mind that Perl doesn't have delegates, but you can get close:

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

Even closer would be:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM