Richtig mit null
Es gibt verschiedene Verwendungsmöglichkeiten null
. Die gebräuchlichste und semantisch korrekte Methode besteht darin, sie zu verwenden, wenn Sie einen einzelnen Wert haben oder nicht . In diesem Fall ist ein Wert entweder gleich null
oder etwas Sinnvolles wie ein Datensatz aus einer Datenbank oder so.
In diesen Situationen verwenden Sie es dann meistens so (in Pseudocode):
if (value is null) {
doSomethingAboutIt();
return;
}
doSomethingUseful(value);
Problem
Und es hat ein sehr großes Problem. Das Problem ist, dass doSomethingUseful
der Wert zum Zeitpunkt des Aufrufs möglicherweise noch nicht überprüft wurde null
! Wenn dies nicht der Fall ist, stürzt das Programm wahrscheinlich ab. Und der Benutzer kann möglicherweise nicht einmal gute Fehlermeldungen sehen, die mit so etwas wie "schrecklicher Fehler: Wert gesucht, aber null!" (nach dem Update: obwohl es möglicherweise noch weniger informative Fehler gibt Segmentation fault. Core dumped.
, oder schlimmer noch, keine Fehler und falsche Manipulationen bei Null in einigen Fällen)
Das Vergessen, Schecks zu schreiben null
und mit null
Situationen umzugehen , ist ein äußerst häufiger Fehler . Aus diesem Grund null
sagte Tony Hoare, der im Jahr 2009 auf einer Softwarekonferenz namens QCon London erfunden hatte , dass er 1965 den Milliarden-Dollar-Fehler begangen habe:
https://www.infoq.com/presentations/Null-References-The-Billion-Dollar- Fehler-Tony-Hoare
Das Problem vermeiden
Einige Technologien und Sprachen machen es null
unmöglich, die Überprüfung auf unterschiedliche Weise zu vergessen, wodurch die Anzahl der Fehler verringert wird.
Zum Beispiel hat Haskell die Maybe
Monade anstelle von Nullen. Angenommen, dies DatabaseRecord
ist ein benutzerdefinierter Typ. In Haskell kann ein Wert vom Typ Maybe DatabaseRecord
gleich Just <somevalue>
oder gleich sein Nothing
. Sie können es dann auf verschiedene Arten verwenden, aber unabhängig davon, wie Sie es verwenden, können Sie keine Operation anwenden, Nothing
ohne es zu wissen.
Diese Funktion heißt zum Beispiel zeroAsDefault
return x
für Just x
und 0
für Nothing
:
zeroAsDefault :: Maybe Int -> Int
zeroAsDefault mx = case mx of
Nothing -> 0
Just x -> x
Christian Hackl sagt, C ++ 17 und Scala haben ihre eigenen Wege. Vielleicht möchten Sie also herausfinden, ob Ihre Sprache so etwas enthält, und es verwenden.
Nullen sind immer noch weit verbreitet
Wenn Sie nichts Besseres haben, ist die Verwendung null
in Ordnung. Pass einfach weiter auf. Typdeklarationen in Funktionen helfen Ihnen sowieso etwas.
Auch das mag nicht sehr progressiv klingen, aber Sie sollten prüfen, ob Ihre Kollegen null
etwas anderes verwenden möchten . Sie sind möglicherweise konservativ und möchten aus bestimmten Gründen möglicherweise keine neuen Datenstrukturen verwenden. Zum Beispiel die Unterstützung älterer Sprachversionen. Solche Dinge sollten in den Codierungsstandards des Projekts deklariert und ordnungsgemäß mit dem Team besprochen werden.
Auf Ihren Vorschlag
Sie schlagen vor, ein separates boolesches Feld zu verwenden. Aber Sie müssen es trotzdem überprüfen und können immer noch vergessen, es zu überprüfen. Hier gibt es also nichts zu gewinnen. Wenn Sie noch etwas anderes vergessen können, z. B. beide Werte jedes Mal aktualisieren, ist es noch schlimmer. Wenn das Problem des Vergessens, nach etwas zu suchen, null
nicht gelöst ist, hat es keinen Sinn. Vermeiden null
ist schwierig und Sie sollten es nicht so machen, dass es noch schlimmer wird.
Wie man nicht null benutzt
Schließlich gibt es übliche Möglichkeiten, um null
falsch zu verwenden . Eine Möglichkeit besteht darin, es anstelle von leeren Datenstrukturen wie Arrays und Strings zu verwenden. Ein leeres Array ist ein richtiges Array wie jedes andere! Es ist fast immer wichtig und nützlich, dass Datenstrukturen, die mehreren Werten entsprechen können, leer sein können, dh eine Länge von 0 haben.
Aus algebraischer Sicht ist eine leere Zeichenfolge für Zeichenfolgen ähnlich wie 0 für Zahlen, dh Identität:
a+0=a
concat(str, '')=str
Mit einer leeren Zeichenfolge können Zeichenfolgen im Allgemeinen zu einem Monoid werden:
https://en.wikipedia.org/wiki/Monoid
Wenn Sie sie nicht erhalten, ist sie für Sie nicht so wichtig.
Lassen Sie uns nun anhand dieses Beispiels sehen, warum es für die Programmierung wichtig ist:
for (element in array) {
doSomething(element);
}
Wenn wir hier ein leeres Array übergeben, funktioniert der Code einwandfrei. Es wird einfach nichts tun. Übergeben wir null
hier jedoch ein , kommt es wahrscheinlich zu einem Absturz mit der Fehlermeldung "Kann Null nicht durchlaufen, sorry". Wir könnten es einpacken, if
aber das ist weniger sauber, und Sie könnten vergessen, es zu überprüfen
Wie gehe ich mit null um?
Was doSomethingAboutIt()
zu tun ist und insbesondere, ob eine Ausnahme ausgelöst werden soll, ist ein weiteres kompliziertes Problem. Kurz gesagt, es hängt davon ab, ob null
ein akzeptabler Eingabewert für eine bestimmte Aufgabe vorhanden war und was als Antwort erwartet wird. Ausnahmen sind für Ereignisse, die nicht erwartet wurden. Ich werde nicht weiter auf dieses Thema eingehen. Diese Antwort ist schon sehr lang.
std::optional
oder verwendenOption
. In anderen Sprachen müssen Sie möglicherweise selbst einen geeigneten Mechanismus erstellen, oder Sie greifen auf einennull
ähnlichen oder einen ähnlichen Mechanismus zurück, weil er idiomatischer ist.