W Perl podprogramy przyjmują argumenty przez specjalną zmienną-tablicę @_, do której automatycznie trafiają wszystkie przekazane parametry. Cechą charakterystyczną Perla jest to, że parametry trafiają do @_ przez referencję, co oznacza, że zmiana elementów wewnątrz funkcji zmienia ich wartości na zewnątrz.
Aby uniknąć nieoczekiwanych zmian przekazanych danych, zaleca się kopiowanie parametrów do zmiennych:
sub sum { my ($a, $b) = @_; return $a + $b; }
Funkcje Perl zawsze zwracają listę wartości, a wynik funkcji to ostatnia obliczona lista lub jawna instrukcja return.
sub minmax { my ($x, $y) = @_; return ($x < $y ? $x : $y, $x > $y ? $x : $y); } my ($min, $max) = minmax(4, 7); # $min = 4; $max = 7
Jeśli wywołać funkcję w kontekście skalarnym — zwróci liczbę zwróconych elementów, jeśli wyniku nie ująć w skalar.
Jak przekazać dużą liczbę zmiennych do funkcji Perl, aby przypadkowo nie zmienić wartości zmiennych źródłowych?
Niekoniecznie odpowiadają: "Należy po prostu kopiować argumenty do zmiennych tak, jak zwykle!"
Prawidłowa odpowiedź:
Kopiowanie działa tylko dla skalarów. Jeśli pracujesz z tablicami lub haszami, użyj referencji, aby zarządzać przekazywaniem danych w sposób jawny i unikać kopii przez referencję:
sub modify { my ($arr_ref) = @_; push @$arr_ref, 'new'; # zmienia oryginalną tablicę } my @data = (1, 2, 3); modify(\@data); # teraz @data = (1, 2, 3, 'new')
Historia
Historia 1
W dużym skrypcie do przetwarzania raportów wewnętrzna funkcja zmieniała wartości elementów tablicy przekazanej z głównego programu. W rezultacie, po wykonaniu funkcji, dane źródłowe zostały zniekształcone. Błąd polegał na tym, że autor funkcji nie robił kopii wartości wejściowych, sądząc, że zmiany będą lokalne — co jest nieprawdziwe dla @_ z tablicami.
Historia 2
Podczas migracji skryptów z Perla 4 (gdzie zmienne były kopiowane inaczej) zespół napotkał problem: przekazywanie zagnieżdżonych haszy prowadziło do nieoczekiwanej "wypłaty" danych między wywołaniami podprogramów — modyfikacja pól hasza w jednej funkcji wpływała na inne fragmenty kodu. Przyczyną była referencja do hasza w liście @_.
Historia 3
Programista zaimplementował funkcję, która zwraca tablicę wyników, ale w miejscu wywołania użył kontekstu skalarnego:
$count = func(@params);. Oczekiwano, że zmiennej przypisze wartość pierwszego zwróconego elementu, a w rzeczywistości w$countznalazła się liczba elementów w liście, co doprowadziło do opóźnień w obliczeniach i zamieszania.