W Perl nie ma wbudowanej składni dla tablic wielowymiarowych, jak to jest zrealizowane w niektórych innych językach. Zamiast tego stosuje się tablice tablic, gdzie każdy element najwyższego poziomu jest odniesieniem do innej tablicy. Taka organizacja pozwala elastycznie modelować tabele, macierze i inne struktury danych wymagające wymiarowości lub większej zagnieżdżenia.
Początkowo Perl był opracowywany do przetwarzania tekstu i pracy z prostymi strukturami, ale po wprowadzeniu odniesień (od Perl 5) programiści zyskali możliwość budowania złożonych zagnieżdżonych struktur - na przykład tablic tablic (array of arrays) lub haszy tablic.
Największe zaskoczenie dla nowych użytkowników: próba stworzenia tablicy o dwóch wymiarach w prosty sposób - na przykład, deklarując @matrix = ( (1,2), (3,4) ). Takie podejście nie da pożądanego rezultatu, ponieważ elementy będą rozpakowywane jako wartości skalarne, a nie jako zagnieżdżone struktury. Często popełnia się również błąd przy kopiowaniu tablic: płytkie kopiowanie prowadzi do nieoczekiwanych efektów ubocznych.
W Perl tablice wielowymiarowe buduje się poprzez odniesienia do tablic. Poprawna inicjalizacja wygląda tak:
my @matrix; for my $i (0..2) { for my $j (0..2) { $matrix[$i][$j] = $i * $j; } } # Dostęp do elementu: $matrix[1][2]
Lub poprzez anonimowe odniesienia:
my $matrix = [ [1,2,3], [4,5,6], [7,8,9] ]; print $matrix->[1][2]; # 6
Kluczowe cechy:
Czy można tworzyć tablice wielowymiarowe bez odniesień, po prostu deklarując nawiasy wewnątrz nawiasów, jak w innych językach?
Nie. W takim przypadku Perl dereferencjonuje elementy jak zwykłą listę. Tylko użycie odniesień jest poprawne.
Przykład niepoprawnego kodu:
my @matrix = ((1,2,3),(4,5,6),(7,8,9)); # Elementy są w jednym rzędzie print $matrix[3]; # 4, a nie [4,5,6] — niepoprawne działanie
Poprawny sposób:
my @matrix = ( [1,2,3], [4,5,6], [7,8,9] ); print $matrix[1][2]; # 6
Co się stanie, jeśli skopiujesz tablicę tablic prostym przypisaniem?
Kopiowany jest tylko najwyższy poziom, zagnieżdżone tablice będą odnosić się do tych samych obszarów pamięci.
Przykład:
my @a = ( [1,2], [3,4] ); my @b = @a; $a[0][0] = 99; print $b[0][0]; # 99, chociaż oczekiwano 1 — płytkie kopiowanie!
Czy można "głęboko" skopiować zagnieżdżoną tablicę wbudowanymi siłami Perla?
Nie, Perl nie zapewnia standardowego operatora głębokiego kopiowania dla zagnieżdżonych struktur. Należy używać modułu Storable lub funkcji rekurencyjnej.
Przykład z Storable:
use Storable 'dclone'; my $deepcopy = dclone(\@matrix);
Programista tworzy dwuwymiarową macierz prostym zadeklarowaniem tablicy i kopiuje ją przypisaniem:
my @m1 = ([1,2],[3,4]);
my @m2 = @m1;
$m1[0][0] = 77;
print $m2[0][0];
Zalety:
Wady:
Użycie modułu Storable do głębokiego kopiowania:
use Storable 'dclone'; my @m1 = ([1,2],[3,4]); my $m2 = dclone(\@m1); $m1[0][0] = 77; print $m2->[0][0]; # 1
Zalety:
Wady: