【问题标题】:Wrap perl's sort function in an object将 perl 的排序函数包装在一个对象中
【发布时间】:2015-01-21 03:29:13
【问题描述】:

我正在尝试在我的一个(面向对象的)包中提供一个排序功能,该包接受一个块并像标准 Perl sort 一样提供 $a 和 $b。

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

# 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
}

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

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 的同时做我想做的事情?

【问题讨论】:

    标签: perl sorting block


    【解决方案1】:

    大部分时间。

    要使用bare-block-as-subroutine 语法,您需要使用&amp; prototype。一般来说,您应该避免使用原型,但是将子例程作为裸块传递是少数可以接受的情况之一。不幸的是,因为它们必须在编译时确定和应用,所以原型不适用于方法。所以你必须使用完整的匿名子例程语法sub { ... }

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

    $a$b 是声明排序子例程的包的全局变量(假设这是Some::Caller)。在你的类中运行时,sort 将设置$My::Object::a$My::Object::b,但子例程将寻找$Some::Caller::a$Some::Caller::b。您可以通过将他们的 $a$b 别名为您的 $a$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 在块的持续时间内制作一个全局的临时副本,这包括其他调用的子例程,因此这将影响排序。然后,当方法完成时,值将恢复为原来的值。

    Perl 全局变量存储在typeglobs 中,其中包含所有同名的全局变量。 *a 包含 $a@a%a。通过复制调用者的 typeglob,当$My::Object::a 改变时,调用者的$a 也会改变。它们是别名。

    *{...} 语法允许您使用另一个变量或表达式按名称获取全局变量。这称为symbolic reference。现在我们可以拨打来电者的*a。使用这种语法通常是一个错误,所以你必须关闭 strict 否则 Perl 不会让你这样做。

    【讨论】:

    • 欣赏您在 SO 上的帖子。
    • The *{...} syntax references a global variable by its name. 这似乎是一种描述这种语法的有趣方式——尤其是在解释了 typeglob 是什么之后。该语法是编写 typeglob 的另一种方式,其中 typeglob 表示具有指定名称的所有全局变量.....
    • 将当前包的所有全局 'a' 变量 typeglob *a 分配给调用者的所有全局 'a' 变量 typeglob i> *{caller.'::a'} 使当前包的全局“a”变量成为调用包的全局“a”变量的别名。这意味着当您更改当前包中的全局“a”变量时,它会更改调用者包中的全局“a”变量。*
    • @7stud 是的,*{...} 是一个 typeglob。它也是一个象征性的参考。我不得不解释两者,它们只是在单独的段落中。我称它们为“globs”,也许我应该使用更恰当的名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    相关资源
    最近更新 更多