Ответ 1
Здесь присутствует случай с тонким краем: внутри foreach
циклов или выражений map
переменная по умолчанию $_
имеет псевдоним с исходным значением. Например.
@nums = 1..5;
@foo = map { $_ *= 2 } @nums;
# both @foo and @nums contain 2, 4, 6, 8, 10 now.
Однако константы не являются допустимыми lvalues, поэтому мы не могли этого сделать, например
@foo = map { $_ *= 2 } 1, 2, 3, 4, 5;
# Modification of read-only value
Массив @_
также сглаживается с исходными значениями, поэтому представьте себе следующие случаи кросс:
sub buggy (&@) { my $cb = shift; map $cb->($_), @_ };
buggy { $_ *= 2 } 1, 2, 3; # Modification of read-only value attempted
buggy { $_[0] *= 2} 1, 2, 3; # ditto
my @array = 1 .. 5;
buggy { $_ *= 2 } @array; # @array now is 2, 4, 6, 8, 10
buggy { $_[0] *= 2 } @array; # ditto
Псевдонимы являются транзитивными, поэтому внутренний $_[0]
псевдоним $_
, который сглажен внешнему $_[0]
, который является псевдонимом для константы 1
/$array[0]
.
Итак, что делает local $_ = $_[$_]
здесь?
- Он делает копию значения, тем самым избегая этого безумного поведения псевдонимов
- Он показывает намерение сделать
$_
видимым для обратного вызова.
Обеспечение семантики копирования (таким образом, избегая неожиданных побочных эффектов) кажется естественным для Perl, поэтому эта функция хорошо разработана и не особенно перегружена.
(Примечание: map {local $_ = $_; ...} @_
было бы достаточно, чтобы сделать копию)