Arrays van arrays, hashes van hashes en andere complexe gegevensstructuren worden in Perl gebouwd met behulp van verwijzingen. Deze aanpak maakt het gemakkelijk om hiërarchische/vertakte structuren te creëren, maar vereist voorzichtigheid bij het aanspreken, kopiëren en wijzigen, omdat standaard de verwijzing wordt opgeslagen en niet de inhoud.
Oorspronkelijk ondersteunde Perl alleen platte arrays en hashes, zonder nesteling. Later kwam er ondersteuning voor verwijzingen, waardoor elke combinatie mogelijk werd: arrays van arrays, hashes van hashes, structuren zoals "boom", "graf" etc.
Werken met complexe structuren vereist dat men zich herinnert dat de bewerkingen voor aanspreken, schrijven en kopiëren met verwijzingen werken. Fouten ontstaan vaak door verwarring tussen het element en de verwijzing naar het element. Dit leidt tot talrijke bugs, bijvoorbeeld, het wijzigen van gegevens op één plek heeft invloed op de gehele structuur, als de verwijzing door meerdere delen van het programma tegelijkertijd wordt gebruikt.
Voor het maken van een array van arrays:
my @matrix; for my $i (0..2) { for my $j (0..2) { $matrix[$i][$j] = $i * $j; } } print $matrix[1][2]; # 2
Voor een hash van hashes:
my %data; $data{'user1'}{'name'} = 'Alex'; $data{'user1'}{'age'} = 20;
Gemengde structuren:
my %complex = ( 'list' => [1, 2, 3], 'map' => { foo => 'bar' }, );
Wat gebeurt er als je probeert een array aan een andere toe te wijzen om de structuur te kopiëren?
Zo'n toewijzing kopieert geen geneste structuren, maar alleen de verwijzingen ernaar (dat wil zeggen, er vindt een "oppervlakkige kopie" plaats).
my @a = ([1,2], [3,4]); my @b = @a; $a[0][0] = 99; printf "$b[0][0] "; # Geeft 99 weer, omdat @b verwijzingen naar dezelfde arrays bevat als @a
Wat is het verschil tussen toegang tot een element als $array[$i] versus $array->[$i]?
De eerste variant werkt als we een array hebben, de tweede werkt als we een scalaar hebben die naar een array verwijst. Voor geneste structuren is de meest voorkomende syntaxis de pijl ($foo->[0]).
Waarom kun je gewoon geen kopie van de structuur maken met dclone in de standaard Perl?
Omdat dclone niet is opgenomen in de basislevering van Perl. Voor het maken van diepe kopieën van complexe structuren gebruikt men de Storable-module en de functie dclone:
use Storable 'dclone'; my $deep_copy = dclone(\%complex);
In een project worden arrays van arrays gekopieerd via gewone toewijzing (@copy = @org), en na een reeks wijzigingen merken ze plotseling dat de gegevens van de "origineel" zijn gewijzigd samen met de kopie.
Voordelen:
Nadelen:
Men gebruikt de Storable-module en de functie dclone voor het kopiëren van arrays en hashes, waarbij dit expliciet wordt gedocumenteerd in de code en duidelijk wordt onderscheiden waar de verwijzing is en waar deze niet is.
Voordelen:
Nadelen: