Perl: массив splice () с использованием подпрограммы - PullRequest
3 голосов
/ 06 марта 2012

Мне нужна подпрограмма, которая полностью удаляет элемент массива вместо .Сбой следующего кода:

sub del
{
    splice(@_,2,1);
}

@array=(0..5);
print "@array"."\n";
del(@array);
print "@array"."\n";

Тот же массив печатается снова, т.е. элемент не был удален.Однако, если я использую splice() в основном теле программы вместо вызова подпрограммы, это работает.

Ответы [ 2 ]

14 голосов
/ 06 марта 2012

Хотя скалярные элементы @_ связаны с данными, которые передаются, сам @_ является другой переменной.Это означает, что $_[1] = "foo" изменит $_[1], но push @_, "foo" не изменит @_.В противном случае my $self = shift будет плохим.

Вам необходимо передать массив в качестве ссылки.

sub del {
    my $array_ref = shift;

    splice @$array_ref, 2, 1;

    return;
}

del \@array;

Если вам абсолютно необходимо сохранить интерфейс del @array, это одиниз немногих мест, где уместно использовать прототип.

sub del(\@) {
    my $array_ref = shift;

    splice @$array_ref, 2, 1;

    return;
}

del @array;

Прототип \@ сообщает Perl передать @array по ссылке.Я бы рекомендовал против сделать это по двум причинам.Во-первых, у прототипов есть куча предостережений, которые делают их бесполезными.

Что еще более важно, это делает неочевидным, что del изменит свои аргументы.Обычно определяемые пользователем функции Perl копируют свои аргументы, поэтому вы можете посмотреть на foo @array и быть уверенным, что @array не будет изменен на foo.Это позволяет быстро просмотреть код для вещей, которые будут влиять на переменную.Эталонный прототип выбрасывает это в окно.Теперь каждая функция должна быть проверена на возможную скрытую передачу по ссылке.

1 голос
/ 06 марта 2012

Ответ можно найти с помощью perldoc perlsub:

Все переданные аргументы отображаются в массиве @ . Поэтому, если вы вызывается функция с двумя аргументами, они будут храниться в $ [0] и $ [1]. Массив @ является локальным массивом, но его элементы являются псевдонимами для фактических скалярных параметров. В частности, если обновляется элемент $ [0], соответствующий аргумент обновлен (или возникает ошибка, если он не обновляемый). Если аргумент является элементом массива или хеша, которого не было при вызове функции, этот элемент создается только когда (и если) он изменен или ссылка на это взято. (В некоторых более ранних версиях Perl этот элемент создавался независимо от того, был ли ему присвоен элемент.) весь массив @ удаляет этот псевдоним и не обновить любые аргументы.

Короче говоря, отдельные элементы могут быть изменены, но не сам список, если вам нужно, чтобы изменения были видны за пределами подпрограммы. Но вы, вероятно, могли бы вернуть @_, что вернул бы измененный список, который вам затем нужно было бы захватить как возвращаемое значение.

...