Enthält ein nicht initialisierte Hash-Schlüssel einen Standardwert von Null in Perl hat?
-
03-07-2019 - |
Frage
Ich habe Perl-Code ähnlich den folgenden:
# -- start --
my $res;
# run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{
if( $row->[4] =~ /PA/ ) {
$res->{ipv6}{pa}{$row->[2]}++;
} elsif( $row->[4] eq 'PI' ) {
$res->{ipv6}{pi}{$row->[2]}++;
}
}
# -- stop --
An keiner Stelle wird $res
jemals vor gesetzt über die Abfrageergebnisse iterieren noch der Code läuft gut.
Wenn ich print-Anweisungen setzen vor jedem Wert ich Leerzeichen in beiden Fällen aber, wenn die Druckanweisungen kommen, nachdem der Zuwachs angewendet wurde bekomme ich einen Wert von> = 1, je nachdem, wie viele IPv6-Ressourcen der Organisation.
Meine Frage ist, nehme ich dies ein nicht initialisierte Hash-Schlüssel in Perl automatisch einen Wert von Null hat zu bedeuten?
Sorry, wenn es über als Neuling Frage kommt, aber ich bin einfach nicht vertraut mit solchen Konstrukt
d.h. $hashref->{foo}->{bar}++
wobei ein Wert noch werden muss explizit $hashref->{foo}->{bar}
zugeordnet. Vielen Dank im Voraus!
Lösung
Der Wert ist nicht automatisch Null. Der Wert ist zunächst nicht definiert. Allerdings, wenn Sie es wie eine Nummer behandelt (zB gelten ++
es), dann Perl behandelt sie wie Null. Wenn Sie es wie eine Zeichenfolge behandeln (zB gelten .
es), dann Perl behandelt sie wie eine leere Zeichenfolge.
Von perldoc perlsyn
unter 'Erklärungen':
Das einzige, was müssen Sie erklären in Perl sind Berichtsformate und Subroutinen (und manchmal nicht einmal Subroutinen). Eine Variable hält die undefinierter Wert ( „undef“), bis er hat wurde ein definierter Wert zugewiesen, der ist etwas anderes als „undefiniert“. Wann als Nummer verwendet wird, wird „undef“ behandelt als 0; wenn sie als Zeichenfolge verwendet wird, ist es als leere Zeichenfolge behandelt, „“; und wenn als Referenz verwendet das ist nicht wobei zugewiesen, wird es als behandelte Fehler.
Andere Tipps
Um auf Telemachos zu erarbeiten post, werden die nicht initialisierte Werte undefiniert. Die tiefen Teile der Struktur sind autovivified . Dies ist eine praktische Funktion, wo Datenstrukturen werden automatisch für Sie erstellt. Autovivification ist groß, wenn Sie es wollen, aber es kann ein Schmerz, wenn Sie es verhindern wollen. Es gibt viele Tutorials, Artikel und Beiträge rund um das Netz auf autovivification zu verstehen.
So eine undefinierte $ref
und $ref->{ipv6}{pa}{'foo'}++
gegeben wird $ref
einen Wert von zugewiesen werden:
$ref = {
ipv6 => {
pa => {
foo => undef
}
}
};
Dann wird der undef erhöht werden, da undef numifies auf 0, erhalten wir 0 ++, die 1 ist.
Für ein endgültiges Ergebnis:. ref->{ipv6}{pa}{'foo'} == 1
Wenn Sie Warnungen aktiviert ist, (Sie tun use warnings;
, nicht wahr?) Erhalten Sie eine „nicht initialisierte Wert“ Warnung erhalten, wenn Sie auf diesen undefinierten Werten betreiben. Wenn es das gewünschte Verhalten ist der unitialized Wert zu erhöhen, dann können Sie die gewünschte Gruppe von Warnungen aus über einen begrenzten Teil des Codes schalten:
use strict;
use warnings;
my $res;
// run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{ no warnings 'uninitialized';
if( $row->[4] =~ /PA/ ) {
$res->{ipv6}{pa}{$row->[2]}++;
} elsif( $row->[4] eq 'PI' ) {
$res->{ipv6}{pi}{$row->[2]}++;
}
}
Sie können die Warnungen Hierarchie finden in perllexwarn .
Es ist im Grunde nicht definiert, aber so behandelt, als ob es Null war, wenn Sie es erhöhen.
Der Begriff in Perl parlance ist 'autovivified'.
Was möchten Sie wahrscheinlich tun, verwenden Sie die existiert Stichwort :
$res->{ipv6}{pa}{$row->[2]}++ if exists($res->{ipv6}{pa}{$row->[2]});
Es gibt nicht so etwas wie einen nicht initialisierten Hash Schlüssel . Die Sache, die nicht initialisiert werden kann, ist der Wert für einen bestimmten Schlüssel. Ein Hash-Wert ist nur ein skalarer Wert ist; es ist nicht anders als eine Variable wie $foo
.
Es gibt ein paar verschiedene Perl in Ihrem Beispiel Funktionen interagieren.
Am Anfang $res
ist nicht definiert (das heißt hat sie den Wert undef
). Wenn Sie einen nicht initialisierten Wert als Hash-Referenz (wie in $res->{ipv6}...
) Perl „autovivifies“ als eines. Das heißt, Perl erstellt einen anonymen Hash und ersetzt den Wert von undef
mit einem Verweis auf den neuen Hash. Dieser Vorgang wiederholt sich (leise) jedes Mal, wenn der resultierende Wert als Referenz verwenden.
Schließlich autovivify Sie Ihren Weg $res->{ipv6}{pa}{$row->[2]}
, die nicht definiert ist. Denken Sie daran, dass dies nur ein Einzelwert wie $foo
ist. Das Verhalten ist das gleiche wie zu sagen
my $foo;
$foo++;
Perl tut spezielle Dinge, wenn Sie nicht definierte Werte verwenden. Wenn Sie sie als Nummer verwenden, konvertiert Perl sie auf 0, wenn Sie sie als String verwenden, Perl konvertiert sie in das ‚‘ (leerer String). In den meisten Fällen finden Sie eine „Verwendung von nicht initialisierten Wert ...“ Warnung erhalten, wenn Sie Warnungen aktiviert haben (die Sie sollten). Die Autoinkrement Operator (++
) ist ein obwohl Sonderfall. Der Einfachheit halber, wandelt es still um den Wert von undef
vor Erhöhen sie 0
.