Frage

Wenn ich durchlies Programmierung perl, 2. Auflage, Seite 51, Etwas verwirrt mich:

sub newopen {
    my $path = shift;
    local *FH;    #not my!
    open (FH, $path) || return undef;
    return *FH;
}

$fh = newopen('/etc/passwd');

Mein Ich weiß, warum werden wir nicht empfohlen, meine zu verwenden? Bisher kann ich nicht sehen, dass etwas schief geht, wenn wir meine () verwenden.

Vielen Dank!

War es hilfreich?

Lösung

Die trite Antwort ist, dass Sie verwenden müssen local Weil my *FH ist ein Syntaxfehler.

Die "richtige" (aber nicht sehr aufschlussreiche) Antwort ist, dass Sie es falsch machen. Sie sollten lexikalische Dateihandles und die drei Argumentform von verwenden open stattdessen.

sub newopen {
    my $path = shift;
    my $fh;
    open($fh, '<', $path) or do {
        warn "Can't read file '$path' [$!]\n";
        return;
    }
    return $fh;
}

Wirklich zu antworten warum erfordert eine Erläuterung des Unterschieds zwischen lexikalischen und globalen Variablen sowie zwischen dem Umfang einer Variablen und seiner Dauer.

Der Bereich einer Variablen ist der Teil des Programms, in dem sein Name gültig ist. Umfang ist eine statische Eigenschaft. Die Dauer einer Variablen hingegen ist eine dynamische Eigenschaft. Dauer ist die Zeit während der Ausführung eines Programms, dass die Variable existiert und einen Wert hat.

my deklariert eine lexikalische Variable. Lexikalische Variablen haben vom Punkt der Deklaration bis zum Ende des blockierenden Blocks (oder der Datei) einen Umfang. Sie können andere Variablen mit demselben Namen in verschiedenen Bereichen ohne Konflikte haben. (Sie können auch einen Namen in überlappenden Scopes wiederverwenden, aber tun Sie dies nicht.) Die Dauer der lexikalischen Variablen wird die Referenzzählung von Thorugh-Referenz verwaltet. Solange es mindestens einen Verweis auf eine Variable gibt, besteht der Wert, auch wenn der Name in einem bestimmten Bereich nicht gültig ist! my hat auch einen Laufzeiteffekt - es verteilt a Neu Variable mit dem angegebenen Namen.

local ist ein bisschen anders. Es arbeitet mit globalen Variablen. Globale Variablen haben einen globalen Umfang (der Name ist überall gültig) und eine Dauer des gesamten Programms des Programms. Was local tut eine vorübergehende Änderung an der Wert einer globalen Variablen. Dies wird manchmal als "dynamischer Scoping" bezeichnet. Die Änderung beginnt am Punkt der local Erklärung und bestehen bis zum Ende des umschließenden Blocks, nach dem der alte Wert wiederhergestellt wird. Es ist wichtig zu beachten, dass der neue Wert nicht auf den Block beschränkt ist - er ist überall sichtbar (einschließlich Unterprogramme). Die Referenzzählregeln gelten weiterhin, sodass Sie nach Ablauf der Änderung einen Bezug auf einen lokalisierten Wert aufnehmen und aufbewahren können.

Zurück zum Beispiel: *FH ist eine globale Variable. Genauer gesagt ist es ein "Typeglob" - ein Container für eine Reihe globaler Variablen. Ein Typeglob enthält einen Steckplatz für jeden der grundlegenden Variablentypen (Skalar, Array, Hash) plus ein paar andere Dinge. Historisch gesehen verwendete Perl Typeglobs zum Speichern von Dateihandeln und local-Das Unternehmen hat sichergestellt, dass sie sich nicht gegenseitig gepackt haben. Lexikalische Variablen haben keine Typeglobs, weshalb das Sprichwort sagen kann my *FH ist ein Syntaxfehler.

In modernen Versionen von Perl -Lexikalvariablen können und sollten stattdessen als Dateihande verwendet werden. Und das bringt uns zurück zur "richtigen" Antwort.

Andere Tipps

In Ihrem Beispielcode den Anruf zum integrierten Unterroutine open Verwendet ein bloßes Wort als Dateihandle, das dem Äquivalent einer globalen Variablen entspricht. Wie Nathan Fellmans Antwort erklärt, verwendet local Lokalisiert dieses nackte Wort im aktuellen Codeblock, falls eine andere globale Variable mit demselben Namen an anderer Stelle im Skript oder Modul definiert wird. Dies verhindert, dass die zuvor definierte globale Variable durch die neue Erklärung ausgelöscht wird.

Dies war in den alten Perl -Tagen eine sehr häufige Praxis, aber Ab Perl 5.6 ist es weitaus besser, einen Skalar zu verwenden (mit dem my Erklärung, auf die Sie in Ihrer Frage angedeutet haben, um Ihr Dateihandle zu definieren und verwenden Sie außerdem den drei Argumentanruf zu open.

use Carp;
open my $error_log, '>>', 'error.log' or croak "Can't open error.log: $OS_ERROR";

Bemerkenswerterweise beachten Sie, dass es für das Lesen und Schreiben von Standardeingangs-/Ausgängen immer noch besser ist, die beiden Argumente zu verwenden open:

use Carp;
open my $stdin, '<-' or croak "Can't open stdin: $OS_ERROR";

Alternativ können Sie die verwenden IO::File Modul, um den Dateihandle für die Klasse zu segnen:

use IO::File;
my $error_log = IO::File->new('error.log', '>>') or croak "Can't open error.log: $OS_ERROR");

Der Großteil des Kredits geht hier an Damian Conway, Autor des exzellenten Buch Perl Best Practices. Wenn Sie die Perlentwicklung ernst meinen, schulden Sie es sich selbst, dieses Buch zu kaufen.

Warum lesen Sie ein veraltetes Buch? Die 3. Ausgabe ist schon lange aus! Welche Version von Perl verwenden Sie? Die 2. Auflage beschreibt Perl 5.004 (5.4.x) oder so.

Heutzutage sollten Sie die TypeGlob -Notation nicht für Dateihandles verwenden. Verwenden Sie die "lexikalischen Dateihandles" (siehe offen, Ich denke) oder die DateiHandle Modul oder stattdessen eines seiner Verwandten.


Vielen Dank an Michael Schwern und YSth für Kommentare, die hier aufgenommen wurden.

Ich glaube es ist, weil my Zuteilt eine neue Kopie der Variablen im Stapel und ist verloren, wenn Sie den Block beenden. local rettet das Bestehende *FH an anderer Stelle und überschreibt das Bestehende *FH. Es stellt den alten wieder her, wenn Sie den Stapel verlassen. Mit my das *FH Typeglob hat den Umfang, wenn Sie den Block beenden. Mit local Es existiert weiter, sodass Sie es nach der Rückgabe weiter verwenden können.

Ich bin mir dessen nicht 100% sicher, aber vielleicht kann es Sie in die richtige Richtung zeigen.

Siehe lokalisierte Dateihandles hier, Ich denke, das erklärt es.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top