2015-01-21 3 views
5

Я пытаюсь сделать функцию сортировки доступной в одном из моих (объектно-ориентированных) пакетов, который принимает блок и делает доступными $ a и $ b, как стандартный Perl sort.Функция сортировки perl в объекте

Во-первых, упрощенная версия того, что я пытаюсь сделать в пакете, который содержит обернутое функцию сортировки:

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

ответ

8

В основном.

Чтобы использовать синтаксис bare-block-as-subroutine, вам необходимо использовать &prototype. Как правило, вам следует избегать прототипов, но передача подпрограммы в виде оголенного блока является одним из немногих случаев, когда это приемлемо. К сожалению, поскольку они должны быть определены и применены во время компиляции, прототипы не работают над методами. Таким образом, вы должны использовать полный синтаксис подпрограммы анонимного, sub { ... }.

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

$a и $b являются Глобал пакета подпрограмма сортировки была объявлена ​​в (скажем, это Some::Caller). При запуске внутри вашего класса сортировка будет установлена ​​$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 globals хранятся в typeglobs, которые содержат все глобальные переменные с тем же именем. *a содержит $a и @a и %a. При копировании типа glob вызывающего абонента, когда изменяется $My::Object::a, изменяется и номер вызывающего абонента $a. Это псевдонимы.

Синтаксис *{...} позволяет получить глобальную переменную по имени, используя другую переменную или выражение. Это называется symbolic reference. Теперь мы можем получить номер вызывающего абонента *a. Использование этого синтаксиса обычно является ошибкой, поэтому вам нужно отключить strict, иначе Perl не позволит вам это сделать.

+2

Оцените свои должности на SO. –

+0

'Синтаксис * {...} ссылается на глобальную переменную по ее имени.« Это кажется забавным способом описания этого синтаксиса, особенно после объяснения того, что такое * typeglob *. Этот синтаксис - это еще один способ написать * typeglob *, где * typeglob * представляет все глобальные переменные с указанным именем ..... – 7stud

+0

Присвоение всех глобальных переменных «a» текущего пакета * typeglob * '* a', для всех глобальных переменных «a» вызывающего, * typeglob * '* {caller. ':: a'}' заставляет глобальные переменные 'a' текущего пакета становиться псевдонимами для глобальных переменных 'a' вызывающего пакета ,Это означает, что при изменении глобальной переменной «a» в текущем пакете она изменяет глобальную переменную «a» в пакете вызывающего. * – 7stud

Смежные вопросы