ПрограммированиеFull Stack Perl Developer

Какие существуют методы передачи аргументов в подпрограммы Perl и как организовать передачу по ссылке? В чем тонкости работы с @_ и когда передача по ссылке необходима?

Проходите собеседования с ИИ помощником Hintsage

Ответ

В Perl вся аргументация функций происходит через массив @_. При вызове подпрограммы все переданные параметры оказываются внутри этого массива, и исходно — это список, а не копия, то есть если вы меняете $_[0], вы модифицируете оригинал.

Передача по значению:

sub foo { my ($arg1, $arg2) = @_; $arg1 = 10; # Только локальная переменная меняется }

Передача по ссылке:

sub bar { my ($array_ref) = @_; push @$array_ref, 42; } my @data = (1,2,3); bar(\@data); # @data теперь (1,2,3,42)

Тонкости:

  • Если вы хотите изменить оригинальный массив или хэш — передавайте ссылку.
  • Обычные переменные ($foo, $bar) внутри @_ — это псевдонимы оригинальных аргументов, но при распаковке через my ($a, $b) = @_ создаются копии.
  • Для массивов и хэшей при обычной передаче их содержимое разворачивается в список, и вы потеряете границы: нужно передавать ссылку или использовать специфику сдвигов.

Вопрос с подвохом

Если в Perl функцию передать массив так: myfunc(@arr), и внутри функции обратиться к $_[0], что там будет?

Верный ответ: Там будет первый элемент значения массива, а не ссылка на весь массив! Чтобы передать массив как цельный объект, используйте ссылку: myfunc(\@arr).

Пример:

sub print_first { print $_[0], " "; } my @a = qw/foo bar baz/; print_first(@a); # Выведет 'foo', а не ссылку на массив print_first(\@a); # Выведет ARRAY(0x...) — ссылка на весь массив

История

В одном из проектов для модификации глобального хэша вызывали функцию так: update_hash(%global). Внутри изменяли $_[0]. В результате — изменялся лишь локальный срез массива аргументов, а сам глобальный хэш не подвергался модификации. Корректным решением стала передача ссылки: update_hash(\%global).

История

При написании API-фреймворка функциям передавали по много именованных аргументов, используя хэш. Иногда в функцию передавали массив (но не ссылку!), и аргументы "смешивались", что приводило к путанице: myfunc(@arr, %opts). Оказалось, что часть ключей хэша подменялась значениями массива, причём обнаружить ошибку было непросто.

История

При реализации рекурсивного обхода дерева хотели изменять внутренние элементы. В функцию передавали массивы "как есть", не ссылкой. Они создали копии, изменения никак не сказывались на внешнем контексте. Проблема устранилась заменой передач на ссылочный стиль.