假設我有一個實用程序庫(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