Подтвердить что ты не робот

Perl: Специальный массив @_ на самом деле не является псевдонимом?

Специальный массив @_, где присутствуют все аргументы, переданные функции, на самом деле является псевдонимом переданных аргументов. Следовательно, любое изменение, которое мы делаем непосредственно на этот специальный массив @_, также будет отражено в основном. Это ясно.

#!/usr/bin/perl

use warnings;
use strict;

$\="\n";

sub func {
        print \@_;
        $_++ for(@_);
}

my @arr=(2..4);
print \@arr;
func(@arr);
print "@arr";

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

При запуске выше:

ARRAY(0x1b644d0)
ARRAY(0x1b644e0)
3 4 5

Если они указывают на 2 разных местоположения, как изменения, выполненные в @_, отражаются в @arr?

Я вижу что-то не так? Пожалуйста, совет.

4b9b3361

Ответ 1

Это может ответить на ваш вопрос:

use warnings;
use strict;

$\="\n";

sub func {
        print \@_;
        $_++ for(@_);
        print \$_ for @_; 
}

my @arr=(2..4);
print \@arr;
func(@arr);
print "@arr";
print \$_ for @arr;

Выход

ARRAY(0x17fcba0)
ARRAY(0x1824288)
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)
3 4 5
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)

Как вы видите, отдельные аргументы имеют один и тот же адрес, но контейнер не совпадает. Если вы нажмете элемент на @_ в func, @arr не изменится (так что вы можете сделать shift в funct). Таким образом, каждый аргумент является псевдонимом, а элементы массива передаются как отдельные элементы. @_ содержит все элементы, переданные в подпрограмму. Если вы хотите изменить аргумент массива, вам необходимо передать его по ссылке.

Ответ 2

@_ не является псевдонимом; его элементы.

Помните, что

func(@arr);

совпадает с

func($arr[0], $arr[1], ...);

потому что единственное, что может быть передано в sub, это список скаляров, и массив вычисляет список его элементов в контексте списка.

Итак, это означает

func(@arr);

в основном совпадает с

local @_;
alias $_[0] = $arr[0];
alias $_[1] = $arr[1];
...
&func;

Изменение элементов @_ изменит элементы @arr, но добавление и удаление элементов @_ не изменит @arr, поскольку они представляют собой разные массивы.

>perl -E"@a=(4..6); sub { $_[0] = '!';        say @_; }->(@a); say @a;"
!56
!56

>perl -E"@a=(4..6); sub { splice(@_,0,1,'!'); say @_; }->(@a); say @a;"
!56
456