Ich denke , @JackAidley hat es bereits gesagt , aber lassen Sie mich es so formulieren:
ohne Ausnahmen (zB C)
Im normalen Code-Fluss haben Sie:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
In dem Fall "Fehler früh" lautet Ihr Code plötzlich:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Wenn Sie diese Muster erkennen - ein return
in einem else
(oder auch if
) Block, überarbeiten sie sofort so dass der Code in Frage stellt nicht einen hat else
Block:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
In der echten Welt…
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
Dies vermeidet zu tiefes Verschachteln und erfüllt den Fall „Früh ausbrechen“ (hilft dabei, den Verstand und den Code-Fluss sauber zu halten) und verletzt nicht das „wahrscheinlichere if
Teil in das Teil einfügen “, da es einfach keinen else
Teil gibt .
C
und aufräumen
Inspiriert von einer Antwort auf eine ähnliche Frage (die das falsch verstanden hat), gehen Sie wie folgt vor, um mit C aufzuräumen. Sie können dort einen oder zwei Austrittspunkte verwenden, hier einen für zwei Austrittspunkte:
struct foo *
alloc_and_init(size_t arg1, int arg2)
{
struct foo *res;
if (!(res = calloc(sizeof(struct foo), 1)))
return (NULL);
if (foo_init1(res, arg1))
goto err;
res.arg1_inited = true;
if (foo_init2(&(res->blah), arg2))
goto err;
foo_init_complete(res);
return (res);
err:
/* safe because we use calloc and false == 0 */
if (res.arg1_inited)
foo_dispose1(res);
free(res);
return (NULL);
}
Sie können sie zu einem Exit-Punkt zusammenfassen, wenn weniger Aufräumarbeiten erforderlich sind:
char *
NULL_safe_strdup(const char *arg)
{
char *res = NULL;
if (arg == NULL)
goto out;
/* imagine more lines here */
res = strdup(arg);
out:
return (res);
}
Diese Verwendung von goto
ist völlig in Ordnung, wenn Sie damit umgehen können; Der Ratschlag, nicht zu verwenden, goto
richtet sich an Personen, die noch nicht selbst entscheiden können, ob eine Verwendung gut, akzeptabel, schlecht, Spaghetti-Code oder etwas anderes ist.
Ausnahmen
Das oben Gesagte handelt von Sprachen ohne Ausnahmen, die ich selbst sehr bevorzuge (ich kann die explizite Fehlerbehandlung viel besser und mit viel weniger Überraschung anwenden). Igli zitieren:
<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)
Aber hier ist ein Vorschlag, wie Sie es in einer Sprache mit Ausnahmen gut machen und wann Sie sie gut verwenden möchten:
Fehlerrückgabe trotz Ausnahmen
Sie können die meisten frühen return
s durch das Auslösen einer Ausnahme ersetzen . Allerdings , Ihr normaler Programmablauf, dh jeden Code Fluss in dem das Programm nicht begegnen, na ja, eine Ausnahme ... eine Fehlerbedingung, etc. zu jagen, wird nicht alle Ausnahmen erhöhen.
Das bedeutet, dass…
# this page is only available to logged-in users
if not isLoggedIn():
# this is Python 2.5 style; insert your favourite raise/throw here
raise "eh?"
… Ist okay, aber…
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… ist nicht. Grundsätzlich ist eine Ausnahme kein Kontrollflusselement . Dies lässt Operations auch komisch aussehen („diese Java ™ -Programmierer weisen uns immer darauf hin, dass diese Ausnahmen normal sind“) und kann das Debuggen behindern (z. B. die IDE anweisen, bei jeder Ausnahme einfach zu brechen). Ausnahmen erfordern häufig, dass die Laufzeitumgebung den Stapel abwickelt, um Rückverfolgungen usw. zu erzeugen. Es gibt wahrscheinlich weitere Gründe dafür.
Das läuft auf Folgendes hinaus: Verwenden Sie in einer Sprache, die Ausnahmen unterstützt, alles, was der vorhandenen Logik und dem vorhandenen Stil entspricht und sich natürlich anfühlt. Wenn Sie etwas von Grund auf neu schreiben, vereinbaren Sie dies frühzeitig. Wenn Sie eine Bibliothek von Grund auf neu schreiben, denken Sie an Ihre Konsumenten. (Verwenden Sie es niemals abort()
in einer Bibliothek.) Aber was auch immer Sie tun, lassen Sie als Faustregel keine Ausnahme auslösen, wenn der Betrieb danach normal (mehr oder weniger) fortgesetzt wird.
Allgemeine Hinweise Ausnahmen
Versuchen Sie zunächst, alle programminternen Ausnahmen zu verwenden, die vom gesamten Entwicklerteam vereinbart wurden. Grundsätzlich planen sie. Verwenden Sie sie nicht im Überfluss. Manchmal ist sogar in C ++, Java ™, Python eine Fehlerrückgabe besser. Manchmal ist es nicht so; benutze sie mit Gedanken.