Подпрограммы Perl принимают параметры в виде плоских списков скаляров. Массив, переданный в качестве параметра, для всех практических целей также является плоским списком. Даже хеш обрабатывается как плоский список из одного ключа, за которым следует одно значение, затем один ключ и т. Д.
Плоский список не передается в качестве ссылки, если вы не сделаете это явно. Тот факт, что изменение $_[0]
изменяет $a[0]
, заключается в том, что элементы @_
становятся псевдонимами для элементов, передаваемых в качестве параметров. Изменение $_[0]
аналогично изменению $a[0]
в вашем примере. Но хотя это примерно аналогично общему понятию «передача по ссылке», поскольку оно применимо к любому языку программирования, оно не передает конкретно ссылку на Perl; Ссылки Perl отличаются (и действительно, «ссылка» - перегруженный термин). Псевдоним (в Perl) является синонимом чего-то, где в качестве ссылки он похож на указатель на что-то.
Как утверждает perlsyn, если вы присваиваете @_
в целом, вы нарушаете его псевдоним. Также обратите внимание, что если вы попытаетесь изменить $_[0]
, а $_[0]
окажется литералом, а не переменной, вы получите ошибку. С другой стороны, изменение $_[0]
изменяет значение вызывающей стороны, если оно является изменяемым. Таким образом, в первом примере изменение $_[0]
и $_[1]
распространяется на @a
, поскольку каждый элемент @_
является псевдонимом для каждого элемента в @a
.
Ваш второй пример немного хитрый. Хэш-ключи неизменны. Perl не предоставляет способ изменить ключ хеша, кроме его удаления. Это означает, что $_[0]
не может быть изменено. Когда вы пытаетесь изменить $_[0]
Perl не может выполнить этот запрос. Вероятно, следует бросить предупреждение, но это не так. Видите ли, плоский список, переданный ему, состоит из unmodifiable-key, за которым следует modifiable-value и т. Д. В основном это не проблема. Я не могу думать ни о какой причине, чтобы изменить отдельные элементы хэша так, как вы демонстрируете; поскольку хэши не имеют определенного порядка, у вас не будет простого контроля над тем, какие элементы в @_
распространяются обратно на какие значения в %a
.
Как вы указали, правильный протокол должен передавать \@a
или \%a
, чтобы их можно было назвать $_[0]->{element}
или $_[0]->[0]
. Несмотря на то, что обозначения немного сложнее, через некоторое время они становятся второй натурой, и, на мой взгляд, гораздо понятнее относительно того, что происходит.
Обязательно посмотрите документацию perlsub . В частности:
Все передаваемые аргументы отображаются в массиве @_
. Следовательно, если вы вызываете функцию с двумя аргументами, они будут сохранены в $_[0]
и $_[1]
. Массив @_
является локальным массивом, но его элементы являются псевдонимами для фактических скалярных параметров. В частности, если элемент $_[0]
обновляется, соответствующий аргумент обновляется (или возникает ошибка, если он не обновляется). Если аргумент является элементом массива или хеша, который не существовал при вызове функции, этот элемент создается только тогда, когда (и если) он был изменен или была взята ссылка на него. (Некоторые более ранние версии Perl создавали элемент независимо от того, был ли ему присвоен элемент.) Присвоение всего массива @_
удаляет этот псевдоним и не обновляет никаких аргументов.