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

Демистификация Glob Perl (*)

В этот вопрос плакат спросил, как сделать следующее в одной строке:

sub my_sub {
    my $ref_array = shift;
    my @array = @$ref_array;
}

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

sub my_sub {
    my $ref_array = shift;
    for (@$ref_array) {
      #do somthing with $_ here
    };

    #use $ref_array->[$element] here
}

Однако в этот ответ один из SO локальных монахов tchrist предложил:

sub my_sub {
  local *array = shift();
  #use @array here
}

Когда я спросил

В попытке узнать уровень Perl на уровне среднего уровня волшебство, могу я спросить, что вы устанавливают, что здесь? Ты установка ссылки на @array на arrayref, который был передан? Как Знаете ли вы, что вы создаете @array и не массивом% или массивом $? Где я могу узнать больше об этом * операторе (Perlop?). Спасибо!

Мне предложили спросить его как новый пост, хотя он действительно дал хорошие ссылки. Так или иначе, здесь идет? Может кто-нибудь объяснить, что назначается тому, что и как получается @array, а не, возможно, массив% или массив $? Спасибо.

4b9b3361

Ответ 1

Назначение glob

*glob = VALUE

содержит некоторую магию, которая зависит от типа VALUE (т.е. возвращаемого значения, скажем, Scalar::Util::reftype(VALUE)). Если VALUE является ссылкой на скаляр, массив, хеш или подпрограмму, тогда будет перезаписана только эта запись в таблице символов.

Эта идиома

local *array = shift();
#use @array here

работает как задокументировано, когда первый аргумент подпрограммы является ссылкой на массив. Если первый аргумент был вместо этого, скажем, скалярной ссылкой, то только назначение $array, а не @array будет зависеть от назначения.

Немного демо script, чтобы узнать, что происходит:

no strict;

sub F {
  local *array = shift;

  print "\@array = @array\n";
  print "\$array = $array\n";
  print "\%array = ",%array,"\n";
  print "------------------\n";
}

$array = "original scalar";
%array = ("original" => "hash");
@array = ("orignal","array");

$foo = "foo";
@foo = ("foo","bar");
%foo = ("FOO" => "foo");

F ["new","array"];        # array reference
F \"new scalar";          # scalar reference
F {"new" => "hash"};      # hash reference
F *foo;                   # typeglob
F 'foo';                  # not a reference, but name of assigned variable
F 'something else';       # not a reference
F ();                     # undef

Вывод:

@array = new array
$array = original scalar
%array = originalhash
------------------
@array = orignal array
$array = new scalar
%array = originalhash
------------------
@array = orignal array
$array = original scalar
%array = newhash
------------------
@array = foo bar
$array = foo
%array = FOOfoo
------------------
@array = foo bar
$array = foo
%array = FOOfoo
------------------
@array =
$array =
%array =
------------------
@array = orignal array
$array = original scalar
%array = originalhash
------------------

Дополнительный документ в perlmod и perldata. Еще в те дни, когда ссылки были частью Perl, эта идиома была полезной для передачи массивов и хэшей в подпрограммы.

Ответ 2

С моим, по общему признанию, знанием о Perl, но я могу отважиться ответить. Оператор * присваивает запись таблицы символов. Насколько я понимаю, @array,% array и $array относятся к одной и той же записи таблицы символов для строки "array", но к различным полям этой записи: поля ARRAY, HASH и SCALAR. Таким образом, назначение local *array = shift; фактически присваивает всю запись таблицы локального символа для "массива" (включая поля ARRAY, HASH и SCALAR) для того, что было передано в вызывающем абоненте.