在对象中包装perl的sort函数 [英] Wrap perl's sort function in an object

查看:64
本文介绍了在对象中包装perl的sort函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在一个(面向对象的)程序包中提供一个排序函数,该程序接受一个块并像标准Perl sort一样使$ a和$ b可用.

I'm trying to make a sort function available in one of my (object-oriented) packages that accepts a block and makes available $a and $b like the standard Perl sort.

首先,我要在包含包装的排序功能的软件包中尝试做的简化版本:

First, a simplified version of what I'm trying to do in the package that contains the wrapped sort function:

# In package My::Object
sub sort {
  my $self = shift;
  my $block = \&{shift @_};

  return sort $block @{$self->{arrayRef}}; # I want to use the passed in block with array data contained in this object
}

然后是一个客户端传递一个示例的示例,该模块定义了要运行排序的比较器:

And then an example of a client passing a block which defines the comparitor to run for the sort:

my $obj = My::Object->new([3, 1, 5, 6, 2, 4]); # As an example, these values will be come arrayRef from above
my @sortedVals = $obj->sort({ $a < $b });

在仍然可以使用Perl的sort的同时,有什么方法可以做我想做的事情?

Is there a way to do what I'm trying to do while still being able to use Perl's sort?

推荐答案

最多.

要使用裸块子例程语法,您需要使用& 原型.通常,您应该避免使用原型,但是将子例程作为裸露的块传递是可接受的几次.不幸的是,由于必须在编译时确定并应用它们,因此原型无法在方法上运行.因此,您必须使用完整的匿名子例程语法sub { ... }.

To use the bare-block-as-subroutine syntax, you need to use the & prototype. Generally you should avoid prototypes, but passing a subroutine as a bare block is one of the few times this is acceptable. Unfortunately, because they must be determined and applied at compile time, prototypes do not work on methods. So you have to use the full anonymous subroutine syntax, sub { ... }.

my @sortedVals = $obj->sort(sub { $a <=> $b });

$a$b是在其中声明了sort子例程的程序包的全局变量(假设这是Some::Caller).在类中运行时,sort将设置$My::Object::a$My::Object::b,但是子例程将在搜索$Some::Caller::a$Some::Caller::b.您可以通过将其$a$b别名为$a$b来解决此问题.

$a and $b are globals of the package the sort subroutine was declared in (let's say this is Some::Caller). When run inside your class, sort will set $My::Object::a and $My::Object::b but the subroutine will be looking for $Some::Caller::a and $Some::Caller::b. You can work around this by aliasing their $a and $b to your $a and $b.

sub sort {
    my $self = shift;
    my $block = shift;

    no strict 'refs';
    local *{caller.'::a'} = *a;
    local *{caller.'::b'} = *b;

    return sort $block @{$self->{arrayRef}};
}

local在块的持续时间内制作一个全局的临时副本,这包括其他调用的子例程,因此将影响排序.然后,该方法完成后,值将恢复为原来的值.

local makes a temporary copy of a global for the duration of the block and this includes other subroutines called, so this will effect the sort. Then when the method is done the value will revert to what it was.

Perl全局变量存储在 typeglobs 中,该变量包含所有全局变量同名. *a包含$a@a%a.通过复制呼叫者的类型范围,当$My::Object::a更改时,呼叫者的$a也将更改.它们是别名.

Perl globals are stored in typeglobs which contain all the global variables with the same name. *a contains $a and @a and %a. By copying the caller's typeglob, when $My::Object::a changes, the caller's $a will change as well. They are aliases.

*{...}语法使您可以使用另一个变量或表达式按名称获取全局变量.这称为符号参考.现在,我们可以到达调用方的*a.使用这种语法通常是一个错误,因此您必须关闭strict,否则Perl将不允许您这样做.

The *{...} syntax lets you get at a global variable by name using another variable or expression. This is called a symbolic reference. Now we can get at the caller's *a. Using this syntax is usually a mistake, so you have to turn off strict else Perl won't let you do it.

这篇关于在对象中包装perl的sort函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆