Option der ganzen Ort unter Verwendung fühlt sich ein wenig umständlich. Mache ich etwas falsch?

StackOverflow https://stackoverflow.com/questions/2476835

  •  21-09-2019
  •  | 
  •  

Frage

Als Ergebnis des Artikels, die ich über die Option Klasse lesen, die Sie Vermeiden Nullpointer hilft, begann ich alles über den Ort zu verwenden. Stellen Sie sich vor etwas wie folgt aus:

var file:Option[File] = None

und später, als ich es verwenden:

val actualFile = file.getOrElse(new File("nonexisting"))
if(actualFile.getName.equals("nonexisting")) { // instead of null checking

}
else { // value of file was good

}

Doing Sachen wie diese fühlt sich nicht alles, was „richtig“ zu mir. Ich habe auch bemerkt, dass .get veraltet geworden. . Ist diese Art von Sachen, was ihr auch mit der Option das tun, oder bin ich auf den falschen Weg?

War es hilfreich?

Lösung

Es ist im Allgemeinen nicht eine gute Idee, Rückkehr Option und dann getOrElse verwenden, um einig Sentinel-Wert zu erzeugen, dass Mittel „nicht gefunden“. Das ist, was Option ist für: um anzuzeigen, dass ein Wert nicht gefunden wird

Option wirklich zeigt seine Kraft, wenn sie in Verbindung mit der funktionalen Programmierung Konstrukte wie map und foreach verwendet. Dies ist besonders potent, wenn sie mit mehreren Optionen zu tun. Angenommen, ich eine Methode schreiben, die einen String und gibt mir wieder eine Datei nimmt, aber nur, wenn die Datei existiert und eine Datei kein Verzeichnis:

import java.io._;
def niceFile1(s: String): File = {
  val f = new File(s);
  if (f.exists && !f.isDirectory) f else null
}
def niceFile2(s: String): Option[File] = {
  val f = new File(s);
  if (f.exists && !f.isDirectory) Some(f) else None
}

Bisher null mit einfacher ist - zumindest bis man vergessen, dass dies könnte Ihnen null und Sie eine NPE bekommen. Wie auch immer, lassen Sie uns nun versuchen, es zu benutzen.

def niceFopen1(s: String) = {
  val f = niceFile1(s);
  if (f!=null) new FileInputStream(f) else null;
}
def niceFopen2(s: String) = niceFile2(s).map(f => new FileInputStream(f))

Sehen Sie, was passiert ist! Im ersten Fall hatten wir Logik Tests von Hand und erstellen temporäre Variablen zu tun. Pfui! Im zweiten Fall hat map die alle schmutzige Arbeit für uns: Keine wurde auf None abgebildet und Some(file) wurde Some(fileinputstream) abgebildet. Easy!

Aber es kommt noch besser. Vielleicht wollen wir die Größe einer ganzen Reihe von Dateien finden:

def totalSize2(ss: Seq[String]) = {
  (0L /: ss.flatMap(niceFile2)){(sum,f) => sum+f.length}
}

Bitte warte, was hier vor sich geht - was ist mit all den None? Haben wir nicht zu achten und mit ihnen umgehen irgendwie? Nun, das ist, wo flatMap kommt: Es schließt sich zusammen alle Antworten in einer einzigen Liste. None ist eine Antwort der Länge Null, so dass er es ignoriert. Some(f) hat eine Antwort - f - so es sie in der Liste setzt. Dann verwenden wir ein alle Längen falten zu addieren - jetzt, dass alle Elemente in der Liste gültig sind. Pretty nice!

Andere Tipps

Es ist eine gute Idee, nicht lösen der Wert des Option, sondern auf anwenden Logik, was auch immer es ist, enthält:

findFile.foreach(process(_))

Grundsätzlich verarbeitet dies ein File wenn ein gefunden wird und tut nichts anders (und ist äquivalent zu Thomas' erstem for Verständnis, weil for compiliert zu einem Aufruf von foreach). Es ist eine kurze Version:

findFile match {
  case Some(f) => process(f)
  case None =>
}

Was mehr ist, die große Sache über dieses ist, dass man Kette Operationen, so etwas wie:

(findLiveFile orElse fileBackupFile orElse findTempFile).foreach(process(_)

In den meisten Fällen würden Sie Musterabgleich verwenden

file match {
   case Some(f) => { .. } //file is there
   case _ => { .. } //file is not there 
}

Wenn Sie nur in der Datei interessiert sind, wenn es da ist man ein für den Ausdruck verwenden kann,

for(f <- file) { //file is there 
}

Sie können dann Kette für Ausdrücke Arbeit auf mehreren Ebenen an Behältern

for{ 
  option <- List(Some(1), None, Some(2))
  f <- option
} yield f

res0: List[Int] = List(1, 2)

Alternativ können Sie IsDefined verwenden und erhalten:

if(option.isDefined) {
   val x = option.get;
} else {
}

get nicht in Scala 2.8.0.Beta-1 veraltet.

Hier ist eine Alternative:

var file:Option[File] = None
// ...
file map (new File(_)) foreach { fh =>
  // ...
}

Wenn Sie jedoch etwas tun müssen, wenn die Datei vorhanden ist, und etwas anderes, wenn dies nicht der Fall, eine match Aussage ist besser geeignet:

var file:Option[File] = None
// ...
file map (new File(_)) match {
  case Some(fh) =>
    // ...
  case None =>
    // ...
}

Das ist so ziemlich das gleiche wie eine if Aussage, aber ich mag es Verkettungs Natur besser für Dinge wie Option, wo ich auch einen Wert extrahieren möge.

Meist Neuformulierung, was alle sagen, aber ich denke, es gibt mindestens 4 verschiedene Situationen auftreten, wenn Sie einen Nullable-var wie diese:

1. Die Datei darf nicht null

load(file.get())

Wird eine Ausnahme auslösen, wenn Sie versuchen, die Datei tatsächlich zu verwenden. Scheitern schnell, yay!

2. Die Datei ist null, aber in diesem Fall haben wir einen vernünftigen Standard:

load(file.getOrElse(new File("/defaultFile")))

3. Zwei Zweige der Logik basierend darauf, ob die Datei vorhanden ist:

  file match {
    case Some(f) => { .. } //file is there
    case _ => { .. } //file is not there 
  }

4. No-op, wenn die Datei null ist, auch bekannt als leise scheitern. Ich glaube nicht, das man sehr oft bevorzugt für mich im wirklichen Leben ist:

for (f <- file) {
//do some stuff
}

Oder vielleicht deutlicher?

if (f.isDefined) {
  //do some stuff
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top