【发布时间】:2010-09-30 19:53:54
【问题描述】:
假设我有一个包含子例程的实用程序库 (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'});
};
但这是相当黑魔法的。好像应该有 一些更好的解决方案。但我还没有找到或想通 还没出来。
【问题讨论】:
-
如果你这样使用调用者,如果定义 sub 的包和调用 other::sort_it 的包不同,它会不会一样坏?
标签: perl sorting namespaces