Действительно ли возврат является целым массивом от неэффективной подпрограммы Perl?

Может быть, это?

fooBar <- function(x,y){
  if(missing(y)) y <- eval.parent(quote(y))
  x + y
}
y <- 1
fooBar(x = 2)
# [1] 3
14
задан brian d foy 15 February 2009 в 21:17
поделиться

7 ответов

Что относительно того, чтобы возвратить ссылку на массив во-первых?

sub getInfo {
  my $array_ref = [];
  push @$array_ref, 'foo';
  # ...
  return $array_ref;
}

my $a_ref = getInfo();
# or if you want the array expanded
my @array = @{getInfo()};

Редактирование согласно комментарию dehmann:

Также возможно использовать нормальный массив в функции и возвратить ссылку на него.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return \@array;
}      
18
ответ дан 1 December 2019 в 06:48
поделиться

Передающие ссылки более эффективны, но разница не является столь же большой как в C++. Сами значения аргументов (который означает: значения в массиве), всегда передаются ссылкой так или иначе (возвращаемый значения, копируются хотя).

Вопрос: это имеет значение? Большую часть времени это не делает. При возврате 5 элементов не беспокойтесь об этом. Если Вы возвращаетесь/передаете 100'000 элементов, используйте ссылки. Только оптимизируйте его, если это - узкое место.

13
ответ дан 1 December 2019 в 06:48
поделиться

Если я смотрю на Ваш пример и думаю о том, что Вы хотите сделать, я используюсь для записи этого этим способом:

sub getInfo {
  my @array;
  push @array, 'obama';
  # ...
  return \@array;
}

Мне как простая версия кажется, когда я должен возвратить большой объем данных. Нет потребности выделить массив снаружи sub как Вы записанный в Вашем первом фрагменте кода, потому что my сделайте это для Вас. Так или иначе Вы не должны делать преждевременной оптимизации как Leon Timmermans предложить.

8
ответ дан 1 December 2019 в 06:48
поделиться

Для ответа на заключительное размышление, нет, Perl не оптимизирует это далеко. Это не может, действительно, потому что возврат массива и возврат скаляра существенно отличаются.

Если Вы будете иметь дело с большими объемами данных или если производительность будет главным беспокойством, то Ваши привычки C будут служить Вам хорошо - передача и возвращать ссылки на структуры данных, а не сами структуры так, чтобы они не должны были быть скопированы. Но, в то время как Leon Timmermans указал, подавляющее большинство времени, Вы имеете дело с меньшими объемами данных, и производительность не состоит в том, что большой соглашение, также - это любым способом кажется самым читаемым.

3
ответ дан 1 December 2019 в 06:48
поделиться

Это - способ, которым я обычно возвращал бы массив.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return @array if wantarray;
  return \@array;
}

Таким образом, это будет работать способ, которым Вы хотите, в скаляре, или перечисляете контексты.

my $array = getInfo;
my @array = getInfo;

$array->[0] == $array[0];

# same length
@$array == @array;

Я не попытался бы оптимизировать его, если Вы не знаете, что это - медленная часть Вашего кода. Даже затем я использовал бы сравнительные тесты для наблюдения, какая подпрограмма на самом деле быстрее.

2
ответ дан 1 December 2019 в 06:48
поделиться

Существует два соображения. Очевидный - то, как большой Ваш массив собирается добраться? Если это - меньше чем несколько дюжин элементов, то размер не является фактором (если Вы не микрооптимизируете для некоторой быстро вызванной функции, но необходимо было бы сделать некоторое профилирование памяти для доказательства этого сначала).

Это - легкая часть. Часто пропущенное второе соображение является интерфейсом. Как возвращенный массив собирается использоваться? Это важно, потому что целое разыменование массива довольно ужасно в Perl. Например:

for my $info (@{ getInfo($some, $args) }) {
    ...
}

Это ужасно. Это намного лучше.

for my $info ( getInfo($some, $args) ) {
    ...
}

Это также предоставляет себя отображению и захвату.

my @info = grep { ... } getInfo($some, $args);

Но возврат массива касательно может быть удобным, если Вы собираетесь выбрать отдельные элементы:

my $address = getInfo($some, $args)->[2];

Это более просто, чем:

my $address = (getInfo($some, $args))[2];

Или:

my @info = getInfo($some, $args);
my $address = $info[2];

Но в той точке, необходимо подвергнуть сомнению, является ли @info действительно списком или хешем.

my $address = getInfo($some, $args)->{address};

То, что Вы не должны делать, имеют getInfo() возвратите массив касательно в скалярном контексте и массиве в контексте списка. Это запутывает традиционное использование скалярного контекста как длина массива, которая удивит пользователя.

Наконец, я включу свой собственный модуль, Метод:: Подписи, потому что это предлагает компромисс для передачи в ссылках на массив, не имея необходимость использовать массив касательно синтаксиса.

use Method::Signatures;

method foo(\@args) {
    print "@args";      # @args is not a copy
    push @args, 42;   # this alters the caller array
}

my @nums = (1,2,3);
Class->foo(\@nums);   # prints 1 2 3
print "@nums";        # prints 1 2 3 42

Это сделано через волшебство Данных:: Псевдоним.

2
ответ дан 1 December 2019 в 06:48
поделиться

Я ничего не знаю о Perl, таким образом, это - нейтральный в отношении языка ответ.

Это, в некотором смысле, неэффективно для копирования массива с подпрограммы в программу вызова. Неэффективность возникает в используемой дополнительной памяти и время, потраченное для копирования данных от одного места до другого. С другой стороны, для всех кроме самых больших массивов, Вы не могли бы волновать и могли бы предпочесть копировать массивы для элегантности, упрямства или любой другой причины.

Эффективное решение - чтобы передача подпрограммы вызов программирует адрес массива. Как я говорю, у меня нет подсказки о поведении Perl по умолчанию в этом отношении. Но некоторые языки предоставляют программисту возможность выбрать который подход.

-4
ответ дан 1 December 2019 в 06:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: