2009-06-18 13 views
7

Quindi, non ho mai saputo questo e voglio ottenere un chiarimento su di esso. So se lo fai

foreach (@list){ 

se si modifica $ _ in quel ciclo interesserà i dati effettivi. Ma, non sapevo che se avete fatto

foreach my $var1 (@list){ 

Se è stata modificata $ var1 nel ciclo cambierebbe i dati effettivi. : -/Quindi, c'è un modo per eseguire il ciclo su @list ma mantenere la variabile una copia di sola lettura, o una copia che, se cambiata, non cambierà il valore in @list?

risposta

10

$var è alternato a ciascun elemento a turno.

Vedi http://perldoc.perl.org/perlsyn.html#Foreach-Loops

Se qualsiasi elemento di LISTA è un lvalue, è possibile modificarlo modificando VAR all'interno del ciclo. Al contrario, se qualche elemento di LIST NON è un lvalue, qualsiasi tentativo di modificare quell'elemento avrà esito negativo. In altre parole, la variabile di indice del ciclo foreach è un alias implicito per ogni elemento nell'elenco in cui si sta effettuando il ciclo.

8

modo più semplice è solo per copiarlo:

foreach my $var1 (@list) { 
    my $var1_scratch = $var1; 

o

foreach my $var1 (map $_, @list) { 

Ma se $ var1 è un riferimento, $ var1_scratch sarà un riferimento alla stessa cosa. Per essere veramente sicuri, dovreste usare qualcosa come Storable :: dclone di fare una copia profonda:

foreach my $var1 (@{ Storable::dclone(\@list) }) { 
} 

(non testato). Quindi dovresti essere in grado di cambiare in modo sicuro $ var1. Ma potrebbe essere costoso se @list è un grande datastructure.

+1

Attenzione, $ var1 non è un riferimento, ma un alias. Vedere la differenza: my $ var2 = \ $ list [0]; stampa "$ var2 \ n"; visualizza SCALARE (0x8171880) – wazoox

+3

@wazoox: intendeva se $ var1 conteneva un riferimento, ad es. se @list contenesse una serie di ref HASH. Anche se rompi l'aliasing, hai ancora un'altra copia di un riferimento alla stessa cosa. –

1

Non so come forzare la variabile come valore-secondario invece di riferimento nell'istruzione foreach stessa. È tuttavia possibile copiare il valore di $_.

#!/usr/perl/bin 
use warnings; 
use strict; 

use Data::Dumper; 

my @data = (1, 2, 3, 4); 

print "Before:\n", Dumper(\@data), "\n\n\n"; 

foreach (@data) { 
    my $v = $_; 
    $v++; 
} 

print "After:\n", Dumper(\@data), "\n\n\n"; 

__END__ 
+2

Dove dici "my $ v = shift;" vuoi dire "my $ v = $ _;'. – dave4420

+0

@Dave Hinton ha corretto l'errore. @Sukotto prova a stampare $ v nel corpo del tuo loop come lo hai originariamente scritto per vedere il tuo errore. –

+0

Sì, intendevo 'my $ v = $ _;' :-( – Sukotto

4

Esso è un alias, non un riferimento. Se si desidera creare i propri alias (al di fuori di per) è possibile utilizzare Data::Alias.

+1

Umm ... +0. Questo è +1 per lo pseudonimo/chiarimento di riferimento e -1 per dare istruzioni su come fare l'opposto di ciò che l'OP chiedeva . (Creazione di un alias anziché rompere l'aliasing.) –

+0

@ Michael Carman ysth aveva già dato la risposta giusta, stavo solo facendo notare che è possibile creare i propri alias. –

2

L'unica differenza tra questi loop:

foreach (@array) { ... } 
foreach my $var (@array) { ... } 

è l'indice del ciclo. L'aliasing è una funzione di foreach, non la variabile implicita $_. Si noti che questo è uno pseudonimo (un altro nome per la stessa cosa) e non un riferimento (un puntatore a una cosa).

Nel semplice (e comune) caso, è possibile interrompere l'aliasing eseguendo una copia:

foreach my $var (@array) { 
    my $copy = $var; 
    # do something that changes $copy 
} 

Questo funziona per i valori scalari ordinari.Per riferimenti (o oggetti) è necessario eseguire una copia profonda utilizzando Storable o Clone, che potrebbe essere costoso. Anche le variabili legate sono problematiche, perlsyn consiglia di evitare completamente la situazione.

+0

o Clone :: More o Clone :: Fast – ysth

+0

o fare una copia in foreach con per il mio $ var (() = @array) – MkV

0

Eseguire una copia di @List nella istruzione for:

foreach my $var1 (() = @list) { 
    # modify $var without modifying @list here 
}