Frage Verwenden von $ @ für die Fehlermeldung, die das Modul übergibt


Ich habe an einer Verzweigung eines CPAN-Moduls gearbeitet, das jetzt nicht mehr gepflegt wird (soweit ich das beurteilen konnte). In diesem Modul verwenden sie $@ um Fehlermeldungen über den Stack zu übermitteln. Mit anderen Worten, sie setzen $@ wenn irgendetwas bei einem Aufruf von Unterprogrammen schief geht, und sie nach dem Anruf prüfen, ob es eingestellt ist. Ich hatte diese Variable vorher noch nie gesehen, aber ich dachte, dass sie nützlich wäre, also habe ich sie auch im Code verwendet. Jetzt habe ich vor kurzem ein wenig mehr darüber gelesen und festgestellt, dass sein Zweck ein wenig enger ist. lesen perlvar (und andere SO Fragen zu diesem Thema) beantwortet dies nicht vollständig für mich, aber, ist es in Ordnung zu verwenden $@ diesen Weg? Einige "Interpunktions" -Variablen, die ich kenne, sollten definitiv nicht auf eine solche allgemeine Weise verwendet werden (einige sogar mit local), ist das einer dieser Fälle, oder bin ich OK, diese Praxis fortzusetzen?


10
2018-04-04 06:13


Ursprung


Antworten:


$@ ist eine relativ "unspezifische" Sondervariable in Perl. Nichts in Perl liest jemals davon $@und es wird nur von einem geschrieben eval {} am Ende blockieren. Dies macht es relativ sicher für eigene Fehler-Signalisierungszwecke zu verwenden.

Insbesondere der Kern IO::Socket Baum der Module verwenden dies, um den Fehler vom Konstruktor anzuzeigen:

use IO::Socket::IP;
my $sock = IO::Socket::IP->new(...) or die "Cannot connect - $@";

Das traditionellere $! ist hier ungeeignet weil $! hat Magie, die die libc-Ebene umschließt errno bauen; Das bedeutet, dass es nur auf eine Ganzzahl gesetzt werden kann errno Wert, auch wenn es entweder als Zahl oder als String gelesen werden kann. Weil manchmal Fehler auftreten können, die sich nicht direkt darauf beziehen errno Werte (in IO::SocketFall, viele Arten von Resolver-Fehler zum Beispiel), manchmal $! ist dafür ungeeignet.


1
2018-04-04 11:42



$@ ist normalerweise nicht explizit festgelegt. Es wird vielmehr automatisch für Sie eingerichtet, wenn eine Ausnahme ausgelöst wird. Von perldoc die:

  • die LISTE

    die löst eine Ausnahme aus. In einem eval Die Fehlermeldung wird eingefügt $@ und das eval wird mit dem undefinierten Wert beendet. Wenn die Ausnahme außerhalb von allen eingeschlossen ist evals, dann druckt die nicht abgefangene Ausnahme LIST auf STDERR und wird mit einem Wert ungleich Null beendet. Wenn Sie den Prozess mit einem bestimmten Beendigungscode beenden müssen, siehe exit.

Beispielsweise,

#!/usr/bin/perl

eval {
    print "Hi\n";
    die "Something went wrong here";
    print "Bye\n";
};
print $@;

Drucke

Hi
Something went wrong here at ./cr22854919 line 5.

Es ist erlaubt zu verwenden $@ um auf diese Weise Fehlernachrichten auf dem Stapel nach oben zu übertragen, als eine Art Versuch-Fang-Mechanismus. Da es sich jedoch um eine globale Variable handelt, sollten Sie sie so schnell wie möglich nach einem eval { } Blockieren Sie, um sicherzustellen, dass kein anderer Code Ihre Behandlung der Ausnahme beeinträchtigt.


Die andere magische Variable, die üblicherweise zur Fehlerbehandlung verwendet wird, ist $!, das funktioniert wie errno in C.

Beispiel:

my $path = "/tmp/no-such-file";
open F, '<', $path
    or print STDERR "$path: $!\n";

Ausgabe:

/tmp/no-such-file: No such file or directory

4
2018-04-04 07:18