Предположим, что у меня есть библиотека утилиты (other
), содержащая подпрограмму
(sort_it
), который я хочу использовать для возврата произвольно отсортированных данных.
Вероятнее всего, это сложнее, но это иллюстрирует
ключевые понятия:
#!/usr/local/bin/perl
use strict;
package other;
sub sort_it {
my($data, $sort_function) = @_;
return([sort $sort_function @$data]);
}
Теперь позвольте использовать его в другом пакете.
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));
Это не работает из-за тонкой проблемы. $a
и $b
являются пакетом
Глобал. Они относятся к $main::a
и $main::b
, когда они завернуты в
закрытие.
Мы могли бы исправить это, сказав вместо этого:
my($sort_by_legs_then_name) = sub {
return ($other::a->{'legs'} <=> $other::b->{'legs'} ||
$other::a->{'animal'} cmp $other::b->{'animal'});
};
Это работает, но заставляет нас жестко указывать имя нашего служебного пакета
везде. Если бы это изменилось, нам нужно было бы запомнить
кода, а не только оператор use other qw(sort_it);
, который, скорее всего,
присутствовать в реальном мире.
Вы можете сразу подумать, чтобы попробовать использовать __PACKAGE__
. Это ветры
оценивая "основное". Таким образом, eval("__PACKAGE__");
.
Вот трюк с использованием 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'});
};
Но это довольно черно-магический. Кажется, что должно быть это лучшее решение. Но я его не нашел или не понял еще нет.