Historia pytania:
W Perl podprogramy od samego początku zostały zaimplementowane bardzo elastycznie: każde wywołanie podprogramu może przyjmować nieograniczoną liczbę parametrów, które są umieszczane w tablicy @_. Takie podejście sprawdza się w zadaniach o różnym stopniu skomplikowania i wspiera dynamikę Perla.
Problem:
Wielu programistów, szczególnie nowicjuszy, napotyka na zamieszanie podczas pracy z @_ — niewłaściwa destrukturyzacja parametrów, przypadkowa zmiana danych wejściowych (ponieważ zmienne są przekazywane przez wartość, a złożone struktury przez referencję), niespójność liczby i typów argumentów. Problemy pojawiają się podczas zwracania różnych typów danych oraz podczas prób realizacji prototypów funkcji.
Rozwiązanie:
Aby uzyskać argumenty, podprogram musi jawnie destrukturyzować je z tablicy @_. Zwracanie wartości odbywa się za pomocą operatora return, a zachowanie zależy od kontekstu (skalarny lub listowy). Aby uniknąć efektów ubocznych, parametry często są przyjmowane jako kopie lub przez referencję, jeśli wymagane jest ich zmienianie wewnątrz podprogramu. W przypadku złożonych struktur stosuje się przekazywanie przez referencję.
Przykład kodu:
sub add { my ($a, $b) = @_; return $a + $b; } sub change_array { my ($arr_ref) = @_; push @$arr_ref, 100; } my @nums = (1, 2, 3); my $sum = add(5, 10); change_array(\@nums); print join(", ", @nums); # 1, 2, 3, 100
Kluczowe cechy:
@_Czy funkcja zmienia parametry przekazane do niej, jeśli pracować z prostymi skalarnymi?
Nie, skalarne są kopiowane przy przekazywaniu, ich zmiany nie wpływają na oryginał. Jednak jeśli argumentem jest referencja, oryginalne dane mogą ulec zmianie.
Czy można zdefiniować domyślne wartości argumentów w podprogramach, jak w innych językach?
Bezpośrednio nie. W Perl należy samodzielnie zrealizować obsługę wartości domyślnych wewnątrz ciała funkcji, używając sprawdzenia defined lub liczby argumentów.
Przykład kodu:
sub foo { my ($arg1, $arg2) = @_; $arg2 //= 10; print "$arg1 $arg2 "; } foo(5); # 5 10
Co się stanie przy bezpośrednim dostępie do @_ bez kopiowania — na przykład, $a = $_[0]?
Taka operacja przypisania tworzy alias: zmiana $a zmieni $[0], i vice versa. Rekomenduje się tworzenie kopii przez my ($a) = @; aby uniknąć nieoczekiwanych zmian.
** Negatywny przypadek
W funkcji przetwarzającej tablicę zapomniano skopiować parametry z @_ do lokalnych zmiennych. W rezultacie zmiana lokalnej zmiennej spowodowała zmianę oryginalnej tablicy, co wywołało błędy w innych częściach programu.
Zalety:
Wady:
** Pozytywny przypadek
W zespole wprowadzono praktykę obowiązkowej destrukturyzacji @_ na początku każdej podprogramy, a duże obiekty przekazywane są tylko przez referencję.
Zalety:
Wady: