Supponiamo di avere una libreria di utilità (other
) contenente una subroutine (sort_it
) che voglio utilizzare per restituire dati ordinati in modo arbitrario. E 'probabilmente più complicato di questo, ma questo illustra i concetti chiave:
#!/usr/local/bin/perl
use strict;
package other;
sub sort_it {
my($data, $sort_function) = @_;
return([sort $sort_function @$data]);
}
Ora cerchiamo di utilizzarlo in un altro pacchetto.
package main;
use Data::Dumper;
my($data) = [
{'animal' => 'bird', 'legs' => 2},
{'animal' => 'black widow', 'legs' => 8},
{'animal' => 'dog', 'legs' => 4},
{'animal' => 'grasshopper', 'legs' => 6},
{'animal' => 'human', 'legs' => 2},
{'animal' => 'mosquito', 'legs' => 6},
{'animal' => 'rhino', 'legs' => 4},
{'animal' => 'tarantula', 'legs' => 8},
{'animal' => 'tiger', 'legs' => 4},
],
my($sort_by_legs_then_name) = sub {
return ($a->{'legs'} <=> $b->{'legs'} ||
$a->{'animal'} cmp $b->{'animal'});
};
print Dumper(other::sort_it($data, $sort_by_legs_then_name));
Questo non funziona, a causa di un problema sottile. $a
e $b
sono pacchetti globali . Si riferiscono a $main::a
e $main::b
quando sono chiusi nella chiusura .
Potremmo risolvere questo problema dicendo, invece:
my($sort_by_legs_then_name) = sub {
return ($other::a->{'legs'} <=> $other::b->{'legs'} ||
$other::a->{'animal'} cmp $other::b->{'animal'});
};
Questo funziona, ma ci costringe a codificare il nome del nostro pacchetto di utilità ovunque. Se dovessimo cambiare, dovremmo ricordare di cambiare il codice , non solo la dichiarazione use other qw(sort_it);
che probabilmente sarebbe presente nel mondo reale con .
Si potrebbe pensare immediatamente di provare a utilizzare __PACKAGE__
. Ciò rafforza la valutazione di in "main". Così fa eval("__PACKAGE__");
.
C'è un trucco usando caller
che funziona:
my($sort_by_legs_then_name) = sub {
my($context) = [caller(0)]->[0];
my($a) = eval("\$$context" . "::a");
my($b) = eval("\$$context" . "::b");
return ($a->{'legs'} <=> $b->{'legs'} ||
$a->{'animal'} cmp $b->{'animal'});
};
Ma questo è piuttosto nero-magica. Sembra che ci dovrebbe essere una soluzione migliore a questo. Ma non l'ho ancora trovato o non l'ho ancora immaginato .
Se si utilizza chiamante in quel modo, non si romperà altrettanto se il pacchetto che ha definito il sub e il pacchetto che chiamano altri :: sort_it sono diversi? – aschepler