Как я могу отменить ссылку на массив и сохранить ее в другой ссылке на массив в Perl? - PullRequest
2 голосов
/ 05 января 2010

У меня есть этот пример:

my $numbers = [ 1, 2, 3, 4, 5, 6 ];
my $newarray = [ reverse @$numbers ];

Этот пример содержит некоторый синтетический код, чтобы сделать массив значений $numbers подходящим для функции reverse. Я хотел бы удалить этот код и сделать что-то вроде этого:

my $newarray = reverse $numbers;

Я знаю, что это не работает, возвращается:

)8936f22x0(YARRA

Есть ли лучший способ обратить массив ссылок в Perl без изменения первой строки ?

UPDATE

my $mails = [ reverse @{$mail_api->GetLogSendMail({ customer_id => $id })} ];

Идея состоит в том, чтобы улучшить вышеприведенную строку кода.

Ответы [ 6 ]

9 голосов
/ 05 января 2010

Если вы можете использовать массив вместо arrayref, попробуйте следующее:

my @newarray = reverse @$numbers;

Код my $newarray = reverse $numbers не работал, потому что reverse вызывается в скалярном контексте, что заставляет его возвращать строку с символами в обратном порядке С reverse инструкция :

В скалярном контексте объединяет элементы LIST и возвращает строковое значение со всеми символами в обратном порядке.

Если вы объявите переменную $ newarray где-то выше, вы можете написать ее следующим образом:

## declare $newarray somewhere else
@$newarray = reverse @$numbers;

Обновление

Может быть, вы захотите создать свою собственную функцию:

sub reverse_by_ref {
    return [ reverse @{$_[0]} ];
}
7 голосов
/ 05 января 2010

Я думаю, что реальная фундаментальная проблема заключается в том, что вы храните $numbers в качестве ссылки на массив и пытаетесь работать с ними как с массивом. Это может быть обычным делом, но это не правильно. Люди делают это для того, чтобы массив постоянно находился в ссылочной форме, но правильный путь - использовать нативную структуру, а не ссылку на нее. В справочной форме scalar, reverse, pop/push/shift/unshift и всех остальных потребуется явное почтение для работы с массивом. Это является общим для всех языков, которые разрешают ссылки на массивы - посмотрите на символьные указатели C против символьных массивов и такие вещи, как оператор sizeof (). На самом деле то, что мы здесь делаем, это использование чрезвычайно удобного синтаксиса анонимного массива perl в ущерб себе.

Это не реальная проблема, но есть небольшие накладные расходы на разыменование и почти неизбежный визуальный элемент отсылки. Теперь перейдем к / справа / ответу. Для этого есть современное решение: autobox. Autobox предоставляет ссылки на все типы, включенные в объектно-подобный синтаксис.

use autobox;
my $arr = [ 1 .. 10 ];
$arr->reverse;

Просто для продолжения, настоящая причина , почему у нас есть анонимный синтаксис массива, состоит в том, чтобы создавать глубокие структуры и избегать передачи массивов (требует помещения их в стек), в большей степени, чем создавать вещи, которые должны быть массивами как массив-ссылки.

  • $foo( [1..100] ) намного быстрее, чем $foo( 1..100 )
  • $arr[1] = [1,2,3] удобнее, чем @temp = 1,2,3; $arr[1] = \@temp
6 голосов
/ 05 января 2010

У вас есть несколько вариантов.

Не пытайтесь втиснуть все это в одну строку:

my $mails = [ reverse @{$mail_api->GetLogSendMail({ customer_id => $id })} ];

становится:

my $mails = $mail_api->GetLogSendMail({ customer_id => $id });
@$mails = reverse @$mails;

Если GetLogSendMail достаточно глуп, чтобы возвращать ссылку на массив, с которым вам не следует связываться, вам придется немного изменить это, чтобы создать новый массив:

my $inviolate_mails = $mail_api->GetLogSendMail({ customer_id => $id });
my $mails;  @$mails = reverse @$inviolate_mails;

Чтобы держать все в одной строке, используйте подпрограмму, как предлагает Иван Невоструев:

sub reverse_ref \@ {
    return [ reverse @{$_[0]} ];
}

my $mails = reverse_ref $mail_api->GetLogSendMail({ customer_id => $id });

Если вам нужно загрузить списки операций для ссылок на массивы, рассмотрите возможность создания библиотеки:

package ArrayRef::Util;
# boiler plate skipped.

sub reverse_ref \@ {
    return [ reverse @{$_[0]} ];
}

sub push_ref \@\@ {
    push @{$_[0]}, @{$_[1]};
}

# and so on

Наконец, предложение Эвана Кэрролла autobox тоже помогает:

use autobox;

my $mails = [ $mail_api->GetLogSendMail({ customer_id => $id })->reverse ];

См. Должен ли я использовать autobox в Perl? для получения дополнительной информации об autobox.

2 голосов
/ 05 января 2010

Вы искали что-то вроде этого:

#!/usr/bin/perl

$myNames = ['Jacob', 'Michael', 'Ethan', 'Andrew'];
@reversedNames = reverse(@$myNames); 

print @reversedNames;

взгляните на этот учебник.

0 голосов
/ 05 января 2010

Два вопроса:

  1. Насколько вы контролируете объект $mail_api?
  2. Вам действительно нужно $mails, чтобы быть ссылкой, а не фактическим массивом? Почему так?

Если ответ на 1 равен «some», а 2 - «no», измените метод GetLogSendMail, чтобы он возвращал список вместо ссылки на массив. Тогда ваш код становится простым

my @mails = reverse $mail_api->GetLogSendMail({ customer_id => $id });
0 голосов
/ 05 января 2010

Я не знаю, имеете ли вы контроль над исходным объектом, но если вы это сделаете, как насчет добавления метода ->reverse в этот пакет?

my $mails = $mail_api->GetLogSendMail({ customer_id => $id })->reverse;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...