Załóżmy, że mam bibliotekę narzędzi (other
) zawierającą podprogram (sort_it
), którego chcę użyć do zwrócenia dowolnie sortowanych danych. To chyba bardziej skomplikowany niż ten, ale ten ilustruje kluczowych pojęć:
#!/usr/local/bin/perl
use strict;
package other;
sub sort_it {
my($data, $sort_function) = @_;
return([sort $sort_function @$data]);
}
Teraz użyjmy go w innym opakowaniu.
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));
To nie działa, ze względu na subtelny problem. $a
i $b
są pakietami globals. Odnoszą się one do $main::a
i $main::b
po zamknięciu w zamknięciu w .
Możemy rozwiązać ten problem, mówiąc, zamiast:
my($sort_by_legs_then_name) = sub {
return ($other::a->{'legs'} <=> $other::b->{'legs'} ||
$other::a->{'animal'} cmp $other::b->{'animal'});
};
To działa, ale zmusza nas do hardcode nazwę naszego pakietu użytkowego wszędzie. Gdyby to się zmieniło, musielibyśmy pamiętać, aby zmienić kod , a nie tylko oświadczenie use other qw(sort_it);
, które prawdopodobnie byłby w rzeczywistości rzeczywiste w postaci .
Możesz od razu pomyśleć, aby spróbować użyć __PACKAGE__
. To powoduje, że jest oceniany jako "główny". Tak samo jest z eval("__PACKAGE__");
.
Jest trik, który działa za pomocą caller
:
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'});
};
Ale to raczej czarno-magiczne. Wygląda na to, że powinno być lepsze rozwiązanie tego problemu. Ale jeszcze tego nie znalazłem ani nie wymyśliłem, .
W przypadku korzystania z takiego rozmówcę, nie pęknie, tak samo, jeśli pakiet, który zdefiniował sub i opakowanie, które nazywają inne :: sort_it są różne? – aschepler