我可以在 perl 中调用带有子类比较的超类排序吗?

Eri*_*ett 1 perl subclass subroutine superclass

我想使用使用子类比较函数的超类排序。我试图在以下代码中提炼问题的性质。这不是“生产”代码,而是在此处提供以供说明。它经过测试。

#!/usr/bin/perl
# $Id: foo,v 1.10 2019/02/23 14:14:33 bennett Exp bennett $

use strict;
use warnings;

package Fruit;
use Scalar::Util 'blessed';

sub new {
    my $class = shift;
    my $self = bless({}, $class);
    $self->{itemList} = [];
    warn "Called with class ", blessed $self, "\n";
    return $self;
}

package Apples;

use parent qw(-norequire Fruit);

sub mySort {
    my $self = shift;
    @{$self->{itemList}} = sort compare @{$self->{itemList}};
    return $self;
}

sub compare {
    $a->{mass} <=> $b->{mass};
}

package main;

my $apfel = Apples->new();
push(@{$apfel->{itemList}}, { "name" => "grannysmith", "mass" => 12 });
push(@{$apfel->{itemList}}, { "name" => "macintosh", "mass" => 6 });
push(@{$apfel->{itemList}}, { "name" => "Alkmene", "mass" => 8 });

$apfel->mySort();

for my $f (@{$apfel->{itemList}}) {
    printf("%s is %d\n", $f->{name}, $f->{mass});
}

exit 0;
Run Code Online (Sandbox Code Playgroud)

我想要做的是转移mySort()到抽象超类Fruit。我已经尝试了多种解决$self->compare()子程序的方法,但我运气不佳。

有什么想法吗?

我已经让它调用正确的子程序,但从来没有使用正确的$a$b。我已经将我所有失败的尝试都排除在这个问题之外,希望有人能立即知道如何将 移动mySort()Fruit包装中,以便我可以使用相同的子程序对我的橙子进行分类。

ike*_*ami 5

诸如$_[1] 之类的标点变量被称为“超级全局变量”,因为它们指的是main::命名空间中的变量。[2]换句话说,无论当前的包$_是什么,都是$main::_.

$a并且$b不是超级全球人。它们是普通的包变量。sort填充在其中找到的包的$a$bsort如果sort和 比较函数在不同的包中找到,则会导致问题。这意味着移动mySort到 Fruit:: 将导致sort填充$Fruit::aand $Fruit::b,但您的compare函数读取$Apple::aand $Apple::b

当涉及多个包时,您可以使用几种解决方案,但最简单的是($$)在比较函数上使用原型。这会导致sort将要比较的值作为参数传递,而不是使用$aand $b

package Foo;
my $compare = \&Bar::compare;
my @sorted = sort $compare @unsorted;

package Bar;
sub compare($$) { $_[0] cmp $_[1] }
Run Code Online (Sandbox Code Playgroud)

sort将 sub 作为函数调用,而不是方法。如果您希望将其作为方法调用,则需要一个包装器。

package Foo;
my @sorted = sort { Bar->compare($a, $b) } @unsorted;

package Bar;
sub compare { $_[1] cmp $_[2] }
Run Code Online (Sandbox Code Playgroud)

也就是说,将sort分类器放在一个类中而分类器放在子类中的想法从根本上是有缺陷的。您可能有一个包含 Apples 和 Oranges 的列表,那么您如何确定compare调用哪个方法呢?

package Foo;
my @sorted = sort { ???->compare($a, $b) } @unsorted;

package Bar;
sub compare { $_[1] cmp $_[2] }
Run Code Online (Sandbox Code Playgroud)
  1. 还有一些命名的,例如STDIN

  2. 通过使用完全限定名称(例如$package::_),您可以访问其他包的标点变量。这些没有特别的意义;Perl 本身并不使用它们。