programowanieFull Stack Perl Developer

Jakie są metody przekazywania argumentów do subprogramów w Perl i jak zorganizować przekazywanie przez referencję? Jakie są subtelności pracy z @_ i kiedy przekazywanie przez referencję jest konieczne?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Perl wszystkie argumenty funkcji są przekazywane przez tablicę @_. Podczas wywołania subprogramu wszystkie przekazane parametry znajdują się w tej tablicy i początkowo jest to lista, a nie kopia, co oznacza, że jeśli zmienisz $_[0], modyfikujesz oryginał.

Przekazywanie przez wartość:

sub foo { my ($arg1, $arg2) = @_; $arg1 = 10; # Tylko lokalna zmienna się zmienia }

Przekazywanie przez referencję:

sub bar { my ($array_ref) = @_; push @$array_ref, 42; } my @data = (1,2,3); bar(\@data); # @data teraz (1,2,3,42)

Subtelności:

  • Jeśli chcesz zmienić oryginalną tablicę lub hash — przekazuj referencję.
  • Zwykłe zmienne ($foo, $bar) w @_ są aliasami oryginalnych argumentów, ale przy rozpakowywaniu przez my ($a, $b) = @_ tworzone są kopie.
  • Dla tablic i hashy przy zwykłym przekazywaniu ich zawartość jest rozwijana w liście i stracisz granice: musisz przekazywać referencję lub używać specyfiki przesunięć.

Pytanie z podstępem

Jeśli w Perl funkcji przekażesz tablicę tak: myfunc(@arr), a w środku funkcji odniesiesz się do $_[0], co tam będzie?

Poprawna odpowiedź: Będzie tam pierwszy element wartości tablicy, a nie referencja do całej tablicy! Aby przekazać tablicę jako cały obiekt, użyj referencji: myfunc(\@arr).

Przykład:

sub print_first { print $_[0], " "; } my @a = qw/foo bar baz/; print_first(@a); # Wyświetli 'foo', a nie referencję do tablicy print_first(\@a); # Wyświetli ARRAY(0x...) — referencję do całej tablicy

Historia

W jednym z projektów aby zmodyfikować globalny hash wywoływano funkcję tak: update_hash(%global). Wewnątrz zmieniano $_[0]. W rezultacie — zmieniano tylko lokalny wycinek tablicy argumentów, a sam globalny hash nie był modyfikowany. Poprawnym rozwiązaniem stało się przekazywanie referencji: update_hash(\%global).

Historia

Podczas pisania frameworku API funkcjom przekazywano wiele nazwanych argumentów, używając hasha. Czasami do funkcji przekazywano tablicę (ale nie referencję!), a argumenty "mieszały się", co prowadziło do zamieszania: myfunc(@arr, %opts). Okazało się, że część kluczy hashy była zastępowana wartościami tablicy, a zauważenie błędu było trudne.

Historia

Podczas implementacji rekurencyjnego przeszukiwania drzewa chciano zmieniać wewnętrzne elementy. Do funkcji przekazywano tablice "jak są", nie przez referencję. Tworzono kopie, a zmiany w żaden sposób nie wpływały na kontekst zewnętrzny. Problem rozwiązano poprzez zastąpienie przekazań stylem referencyjnym.