2013-08-06 3 views
17

-this Fragen im Zusammenhang, was ist der Unterschied zwischen einem manuell eingestellt zu undef Listenelement und einem, die von Perl eingestellt wurde, als durch die Zuordnung zu einem größeren Index als die Liste Größe der Größe des diese Liste wuchs, wenn aliased werden? Zum Beispiel, wenn man bedenkt diesen Code:Array-Element automatisch auf undef festgelegt wird nicht geändert, wenn Alias?

@a = (undef, 0); 
@b =(); 
$b[1] = 0; 

print Dumper(@a), "\n", Dumper(@b); 

druckt (wie erwartet, glaube ich):

$VAR1 = undef; 
$VAR2 = 0; 

$VAR1 = undef; 
$VAR2 = 0; 

So sind nicht die Arrays die gleiche? Offensichtlich nicht:

sub change { $_[0] = 1 } 
change(@a); change(@b); 
print Dumper(@a), "\n", Dumper(@b); 

Welche druckt:

$VAR1 = 1; 
$VAR2 = 0; 

$VAR1 = undef; 
$VAR2 = 0; 

Antwort

17

Sie haben einen faszinierenden Randfall gefunden.

Wenn Sie ein Element explizit festlegen, entsteht es zuerst. Wenn ein Array erweitert wird, so dass mehrere Indizes in den Bereich dieses Arrays fallen, werden an diesen Positionen implizit keine Skalare initialisiert. Beispiel:

my @array; 
$array[2] = undef; # this extends the array 
# now elements 0–2 report as `undef`, but only #2 was initalized 

Wenn wir fragen, ob diese Elemente vorhanden sind, erhalten wir:

say "index $_ ", exists $array[$_] ? "exists" : "doesn't exist" for 0 .. 4; 

Ausgang:

index 0 doesn't exist 
index 1 doesn't exist 
index 2 exists 
index 3 doesn't exist 
index 4 doesn't exist 

Diese Optimierung erspart Ihnen die Zuweisung nicht verwendeten Skalare an diesen Positionen; Der Array-Zugriffscode gibt nur undef zurück, wenn dort nichts anderes steht.

Jetzt quadriert dies schlecht mit Funktionsaufrufen. Wenn ein Unterprogramm aufgerufen wird, wird eine flache Liste von Skalaren auf den Stapel gelegt, der dann als @_ zugänglich ist. Es findet hier kein Kopieren statt, daher ist dies ein Alias-Aufruf. Nun, wenn das $_[0] Element in Ihrem Unter zugegriffen wird, gibt es keine skalare hier, so erzeugt es eine neue in @_:

sub crazy { 
    say 1*exists $_[0]; 
    $_[0] = 1; 
    say 1*exists $_[0]; 
} 

my @array; $array[2] = 0; 
crazy @array; 

say 1*exists $array[0]; 

Ausgang:

0 
1 
0 

Intern ein Skalar ist ein Zeiger auf ein SV struct. Diese Zeiger werden auf den Stapel kopiert, so dass eine tatsächliche Änderung des ursprünglichen @array nicht möglich ist.

6

Ein Unterschied besteht darin, dass exists $a[0] wahr ist und exists $b[0] ist falsch.

Verwandte Themen