假设我有一个实用程序库(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'});
};
但是,这是相当黑魔法。这似乎应该是 一些更好的解决方案。但是我还没有找到它,或者还没有算出它 。
如果使用来电显示这样的,不会打破它一样多,如果所定义的子包,并调用其他:: sort_it包有什么不同? – aschepler 2010-09-30 01:31:10