In Perl ermöglicht die foreach-Schleife das bequeme Durchlaufen von Array-Elementen, wobei die Schleifenvariable standardmäßig ($_ oder explizit angegeben) auf das Array-Element verweist und nicht dessen Wert kopiert.
Beispiel:
my @arr = (1, 2, 3); foreach my $x (@arr) { $x *= 2; } # @arr ist (2, 4, 6) — die Elemente wurden geändert!
Um tatsächlich eine Kopie des Wertes zu erhalten (und nicht eine Referenz auf das originale Element), müssen Sie der Variablen explizit einen Wert zuweisen:
foreach my $x ( @arr ) { # $x ist eine Referenz auf das Element ... } # ↓↓↓↓ foreach (@arr) { my $copy = $_; ... } # $copy ist eine Kopie, $_ ist eine Referenz auf das Element
Es sollte vermieden werden, dieselbe Variable in mehreren verschachtelten foreach-Schleifen zu verwenden, da sonst unerwartete Nebeneffekte auftreten können.
Ist die Variable in der foreach-Schleife eine unabhängige Kopie, und kann sie sicher im Schleifenrumpf geändert werden?
Normalerweise antwortet man: "Ja, denn die Schleife erstellt selbst die Variable — man kann sie beliebig ändern."
Richtige Antwort:
In Perl ist die Schleifenvariable standardmäßig (z. B. foreach $var (@arr)) ein Alias (Referenz) auf das Array-Element. Jede Änderung der Schleifenvariable führt zu einer Änderung des ursprünglichen Elements!
Um eine temporäre Kopie zu ändern – führen Sie eine explizite Zuweisung innerhalb der Schleife durch:
foreach my $elem (@arr) { my $t = $elem; $t++; # nur die Kopie, das ursprüngliche Array ändert sich nicht }
Geschichte
Geschichte 1
In einer Aufgabe zur Filterung von Datensätzen änderte der Programmierer die Variable seiner Schleife, ohne zu ahnen, dass er die Originaldaten verändert. Die folgenden Berechnungen basierten auf dem geänderten Array, weshalb die Summe der Elemente falsch berechnet wurde. Der Fehler trat erst im Vergleich mit einer Referenzstichprobe auf.
Geschichte 2
Die verschachtelte foreach verwendete dieselbe Variable ($item). Die Variable der inneren Schleife überschreib die Zustände der äußeren, wodurch die Ergebnisse des ersten Durchgangs verloren gingen und ein Teil des Arrays falsche Werte hatte.
Geschichte 3
Ein Array von Referenzen auf Hashes wurde durch foreach durchlaufen, und in jeder Schleife wurde der Schleifenvariable ein neuer Wert zugewiesen. Dadurch wurden die Referenzen "gebrochen" — anstelle von Referenzwerten standen jetzt Skalare, und der nächste Verarbeitungsschritt brach mit einem Typfehler ab.