Verwendung von Null / Nichts / Einheit in Scala

95

Ich habe gerade gelesen: http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

Soweit ich weiß, Nullist dies ein Merkmal und seine einzige Instanz ist null.

Wenn eine Methode ein Null-Argument akzeptiert, können wir ihr nur eine NullReferenz oder nulldirekt übergeben, aber keine andere Referenz, selbst wenn sie ( nullString: String = nullzum Beispiel) null ist .

Ich frage mich nur, in welchen Fällen die Verwendung dieses NullMerkmals nützlich sein könnte. Es gibt auch das Merkmal Nichts, für das ich keine Beispiele mehr sehe.


Ich verstehe auch nicht wirklich, was der Unterschied zwischen der Verwendung von Nothing und Unit als Rückgabetyp ist, da beide kein Ergebnis zurückgeben. Woher weiß ich, welches ich verwenden soll, wenn ich eine Methode habe, die beispielsweise die Protokollierung durchführt?


Haben Sie die Verwendung von Unit / Null / Nothing als etwas anderes als einen Rückgabetyp?

Sebastien Lorber
quelle

Antworten:

80

Sie verwenden Nothing nur, wenn die Methode niemals zurückgegeben wird (was bedeutet, dass sie durch Rückgabe nicht normal abgeschlossen werden kann und eine Ausnahme auslösen kann). Nichts wird niemals instanziiert und kommt dem Typsystem zugute (um James Iry zu zitieren: "Der Grund, warum Scala einen unteren Typ hat, hängt mit seiner Fähigkeit zusammen, Varianz in Typparametern auszudrücken." ). Aus dem Artikel, den Sie verlinkt haben:

Eine andere Verwendung von Nothing ist der Rückgabetyp für Methoden, die niemals zurückkehren. Es macht Sinn, wenn Sie darüber nachdenken. Wenn der Rückgabetyp einer Methode Nothing ist und absolut keine Instanz von Nothing vorhanden ist, darf eine solche Methode niemals zurückgegeben werden.

Ihre Protokollierungsmethode würde Unit zurückgeben. Es gibt eine Werteinheit, damit sie tatsächlich zurückgegeben werden kann. Aus den API-Dokumenten :

Unit ist ein Subtyp von scala.AnyVal. Es gibt nur einen Wert vom Typ Unit () und er wird von keinem Objekt im zugrunde liegenden Laufzeitsystem dargestellt. Eine Methode mit dem Rückgabetyp Unit ist analog zu einer Java-Methode, die für ungültig erklärt wird.

Nathan Hughes
quelle
2
Danke, mit "nie zurück" meinen Sie, dass der Anruf auf unbestimmte Zeit blockiert wird (zum Beispiel die Startmethode des Job Schedulers?)
Sebastien Lorber
3
@ Sabastien: Es wird nicht normal zurückgegeben, es könnte eine Ausnahme auslösen (siehe james-iry.blogspot.com/2009/08/… ). Wenn der blockierende Aufruf nur mit dem Auslösen einer Ausnahme endet, zählt dies. Vielen Dank für die Frage, die geklärt werden musste.
Nathan Hughes
18

Der Artikel, den Sie zitieren, kann irreführend sein. Der NullTyp dient der Kompatibilität mit der virtuellen Java-Maschine und insbesondere mit Java .

Wir müssen diese Scala berücksichtigen :

  • ist vollständig objektorientiert: Jeder Wert ist ein Objekt
  • ist stark typisiert: Jeder Wert muss einen Typ haben
  • muss nullVerweise verarbeiten, um auf Java-Bibliotheken und Code zuzugreifen

Daher wird es notwendig, einen Typ für den nullWert zu definieren , der das NullMerkmal ist und nulldessen einzige Instanz ist.

Der NullTyp ist nur dann besonders nützlich, wenn Sie das Typsystem sind oder auf dem Compiler entwickeln. Insbesondere sehe ich keinen vernünftigen Grund, einen NullTypparameter für eine Methode zu definieren , da Sie nur etwas anderes übergeben könnennull

pagoda_5b
quelle
das ist wahr, also gibt es am Ende keine andere Verwendung von Null?
Sebastien Lorber
@SebastienLorber hat die Antwort bearbeitet. Ich kann keine Verwendung für den durchschnittlichen Entwickler sehen. Vielleicht kann sich jemand anderes etwas Nützliches einfallen lassen.
pagoda_5b
Danke dafür. Wenn wir den Grund für diese Art von Dingen kennen, verstehen wir sie, sonst erinnern wir uns an sie.
Sreekar
Null ist nützlich, wenn Sie einen Typparameter haben und möglicherweise Null zurückgeben möchten, wie in dieser Frage und Antwort . Da Sie davon abgeraten haben, Null in Scala zu verwenden, kommt es jedoch selten vor, dass es möglicherweise auch andere Verwendungen im Typsystem gibt
Daniel Carlsson
15

Haben Sie die Verwendung von Unit / Null / Nothing als etwas anderes als einen Rückgabetyp?


Unit kann wie folgt verwendet werden:

def execute(code: => Unit):Unit = {
  // do something before
  code
  // do something after
}

Auf diese Weise können Sie einen beliebigen Codeblock übergeben, der ausgeführt werden soll.


Nullkann als unterster Typ für jeden Wert verwendet werden, der nullwertfähig ist. Ein Beispiel ist folgendes:

implicit def zeroNull[B >: Null] =
    new Zero[B] { def apply = null }

Nothing wird in der Definition von verwendet None

object None extends Option[Nothing]

Auf diese Weise können Sie Nonejedem Typ eine zuweisen , Optionda Nothingalles erweitert wird.

val x:Option[String] = None
EECOLOR
quelle
OK. Für Ihre Verwendung von Unit hätten Sie einen generischen Typ verwenden können, damit die Ausführung diesen generischen Typ zurückgibt, wenn Ihr Codeblock etwas anderes als unit zurückgibt.
Sebastien Lorber
Wie @drexin in einem Kommentar zu einer anderen Antwort sagte, wird es meistens verwendet, um eine Nebenwirkung anzuzeigen.
EECOLOR
6

Wenn Sie verwenden Nothing, gibt es keine Dinge zu tun (einschließlich Druckkonsole). Wenn Sie etwas tun, verwenden Sie den AusgabetypUnit

object Run extends App {
  //def sayHello(): Nothing = println("hello?")
  def sayHello(): Unit = println("hello?")
  sayHello()
}

... wie man es dann benutzt Nothing?

trait Option[E]
case class Some[E](value: E) extends Option[E]
case object None extends Option[Nothing]
Curycu
quelle
1
Auch Ein der Optionmuss in kovarianter Position sein: trait Option[+E]um Dinge wieval x: Option[Int] = None
vim
5

Ich habe den NullTyp noch nie verwendet , aber Sie verwenden ihn dort Unit, wo Sie ihn auf Java verwenden würden void. Nothingist ein besonderer Typ, denn wie Nathan bereits erwähnt hat, kann es keine Instanz von geben Nothing. Nothingist ein sogenannter Bodentyp, was bedeutet, dass es sich um einen Untertyp eines anderen Typs handelt. Dies (und der Parameter für den kontravarianten Typ) ist der Grund, warum Sie einen beliebigen Wert vor Nil- das ist a List[Nothing]- stellen können, und die Liste wird dann von diesem Elementtyp sein. Noneauch wenn vom Typ Option[Nothing]. Jeder Versuch, auf die Werte in einem solchen Container zuzugreifen, löst eine Ausnahme aus, da dies die einzig gültige Möglichkeit ist, von einer Typmethode zurückzukehren Nothing.

Drexin
quelle
danke Ich wusste nicht, dass None Option [Nothing] erweitert. Es ist in einigen Generika sinnvoll, in denen ein Subtyp Nothing verwenden könnte (ich denke, es ist schwierig, ein Beispiel für Null und Unit zu finden ...)
Sebastien Lorber
Das Gerät wird verwendet, wenn Nebenwirkungen auftreten, z. B. kann die E / A-Monade vom Typ IO[Unit]zum Drucken auf die Konsole und dergleichen sein.
Drexin
Ja, nie die E / A-Monade verwendet, es ist sinnvoll, sie mit Unit zu verwenden (und vielleicht nichts, wenn es eine E / A-Operation ist, die einen unendlichen Strom erzeugt?)
Sebastien Lorber
Nein, dort macht nichts keinen Sinn.
Drexin
3

Nichts wird oft implizit verwendet. Im folgenden Code ist val b: Boolean = if (1 > 2) false else throw new RuntimeException("error") die else- Klausel vom Typ Nothing , einer Unterklasse von Boolean (sowie allen anderen AnyVal). Somit ist die gesamte Zuweisung für den Compiler gültig, obwohl die else- Klausel eigentlich nichts zurückgibt.

Fang Zhang
quelle
1

Hier ist ein Beispiel Nothingvon scala.predef:

  def ??? : Nothing = throw new NotImplementedError

Falls Sie nicht vertraut sind (und Suchmaschinen nicht danach suchen können), ???ist Scalas Platzhalterfunktion für alles, was noch nicht implementiert wurde. Genau wie bei Kotlin TODO.

Sie können beim Erstellen von Scheinobjekten denselben Trick verwenden: Nicht verwendete Methoden mit einer benutzerdefinierten notUsedMethode überschreiben . Der Vorteil der Nichtverwendung ???besteht darin, dass Sie keine Kompilierungswarnungen für Dinge erhalten, die Sie niemals implementieren möchten.

David Leppik
quelle
0

In Bezug auf die Kategorietheorie ist nichts ein Anfangsobjekt und die Einheit ein Endobjekt .

https://en.wikipedia.org/wiki/Initial_and_terminal_objects

Anfangsobjekte werden auch als coterminal oder universal bezeichnet , und Endobjekte werden auch als final bezeichnet .

Wenn ein Objekt sowohl initial als auch terminal ist , wird es als Nullobjekt oder Nullobjekt bezeichnet .

Joe
quelle