所以我有一个Perl课程。它有sort()
方法,我希望它与内置sort()
函数或多或少相同:
$object->sort(sub ($$) { $_[0] <=> $_[1] });
但我不能这样做:
$object->sort(sub { $a <=> $b });
由于范围界定。但是List :: Util模块使用reduce()
执行此操作。我查看了List :: Util模块,他们用no strict 'vars'
做了一些相当讨厌的事情来实现这一点。我试过了,但没有用。
我的理解是reduce()
按照它的方式工作,因为它被导出到适当的命名空间,因此我的类不能这样做,因为该函数在另一个命名空间中非常牢固。这是正确的,还是有一些(无疑是更可怕和不明智的)方式在我的情况下这样做?
答案 0 :(得分:9)
嗯,其他两个答案都是半对的。这是一个实际解决的工作解决方案:
package Foo;
use strict;
use warnings;
sub sort {
my ($self, $sub) = @_;
my ($pkg) = caller;
my @x = qw(1 6 39 2 5);
print "@x\n";
{
no strict 'refs';
@x = sort {
local (${$pkg.'::a'}, ${$pkg.'::b'}) = ($a, $b);
$sub->();
} @x;
}
print "@x\n";
return;
}
package main;
use strict;
use warnings;
my $foo = {};
bless $foo, 'Foo';
$foo->sort(sub { $a <=> $b });
# 1 6 39 2 5
# 1 2 5 6 39
据推测,你可以对一些实际上属于对象的数据进行排序。
你需要caller
魔法,所以你要在调用者的包中本地化$a
和$b
,这是Perl将要查找它们的地方。它正在创建仅在调用该子时存在的全局变量。
请注意,您将使用warnings
获得“仅使用一次”的名称;不管怎样,我确信你可以通过一些箍来避免这种情况。
答案 1 :(得分:4)
您可以使用Sub::Identify找出与coderef相关联的包(它称之为stash_name
)。然后根据需要在该包中设置$ a和$ b。您可能需要在方法中使用no strict 'refs'
才能使其正常工作。
这是Evee的答案被修改为适用于一般情况:
use strict;
use warnings;
package Foo;
use Sub::Identify 'stash_name';
sub sort {
my ($self, $sub) = @_;
my $pkg = stash_name($sub);
my @x = qw(1 6 39 2 5);
print "@x\n";
{
no strict 'refs';
@x = sort {
local (${$pkg.'::a'}, ${$pkg.'::b'}) = ($a, $b);
$sub->();
} @x;
}
print "@x\n";
return;
}
package Sorter;
sub compare { $a <=> $b }
package main;
use strict;
use warnings;
my $foo = {};
bless $foo, 'Foo';
$foo->sort(\&Sorter::compare );
$foo->sort(sub { $b <=> $a });
答案 2 :(得分:1)
您可以使用the local
operator在子例程调用期间设置$a
和$b
的值:
sub sample
{
my $callback = shift;
for (my $i = 0; $i < @_; $i += 2) {
local ($a, $b) = @_[$i, $i + 1];
$callback->();
}
}
sample sub { print "$a $b\n" }, qw(a b c d e f g h i j);
如果你有一个普通的子程序,而不是一个方法,那么你可以使它更像sort
,所以你不需要在你的回调函数之前使用sub
。在函数上使用原型:
sub sample (&@)
然后你打电话给它:
sample { print "$a $b\n" } qw(a b c d e f g h i j);
但是,方法不受原型的影响。