2016-04-18 7 views
5

Ich benutze ziemlich oft die folgende Funktion, um Option[Try[_]] in Try[Option[_]] umzuwandeln, aber es fühlt sich falsch an. Kann eine solche Funktionalität auf idiomatische Weise ausgedrückt werden?Wie man Option [Try [_]] konvertiert, um [Option [_]] auszuprobieren?

def swap[T](optTry: Option[Try[T]]): Try[Option[T]] = { 
    optTry match { 
    case Some(Success(t)) => Success(Some(t)) 
    case Some(Failure(e)) => Failure(e) 
    case None => Success(None) 
    } 
} 

Sagen, ich habe zwei Werte:

val v1: Int = ??? 
val v2: Option[Int] = ??? 

Ich möchte eine Operation machen op auf diesen Werten (die ausfallen können), und dass f unten an Funktion übergeben.

def op(x: Int): Try[String] 
def f(x: String, y: Option[String]): Unit 

ich verwenden in der Regel für das Verständnis für die Lesbarkeit:

for { 
    opedV1 <- op(v1) 
    opedV2 <- swap(v2.map(op)) 
} f(opedV1, opedV2) 

PS. Ich möchte einige schwere Sachen wie Scalaz vermeiden.

+2

Die Definition von 'swap' vernünftig aussieht. Ich bin mir nicht sicher, was du mehr davon willst. –

+3

Ein Gedanke: Diese Operation wird normalerweise (idiomatisch?) 'Sequenz' genannt und nicht' swap'. –

Antwort

2

Sounds wie Try { option.map(_.get) } werden tun, was Sie wollen.

+8

Aus meiner Sicht hat das Auslösen und Abfangen der Ausnahme so viel Overhead (z. B. zur Laufzeit, aber noch wichtiger für Leser), dass die OP-Implementierung vorzuziehen ist, auch wenn sie etwas weniger präzise ist. –

+1

Wie hoch ist der Overhead beim Auslösen einer Exception (über die Instantiierung hinaus und das Ausfüllen des Stacks, was schon jetzt geschehen wäre)? Mir ist nicht bewusst, dass es wesentlich größer ist, als eine Funktion aufzurufen. In jedem Fall, denke ich, wenn man sich mit dem Aufwand beschäftigt, Ausnahmen zu werfen, sollte er "Try" nicht verwenden, um damit zu beginnen. Oder Scala für diese Angelegenheit (es gibt Dinge in Scala, die viel mehr Overhead darstellen und viel schwieriger zu vermeiden sind als Ausnahmen). Bleiben Sie einfach bei "C" und gotos, um sicherzugehen, dass Sie Ihren Overhead minimieren :) – Dima

+1

Deshalb habe ich den Overhead für menschliche Leser betont. Ich schreibe oft nach '.get' Aufrufen auf' Try' oder 'Option' als eine schnelle Messung der Gesundheit eines Projekts, das neu für mich ist, und ich mache keine Ausnahmen, weil die Autoren clever sind, um ein ein paar Zeilen und vermeiden Sie eine Musterübereinstimmung. :) –

0

Diese Variante vermeidet Erneutes Auslösen:

import scala.util.{Failure, Success, Try} 

def swap[T](optTry: Option[Try[T]]): Try[Option[T]] = 
    optTry.map(_.map(Some.apply)).getOrElse(Success(None)) 

swap(Some(Success(1))) 
// res0: scala.util.Try[Option[Int]] = Success(Some(1)) 

swap(Some(Failure(new IllegalStateException("test")))) 
// res1: scala.util.Try[Option[Nothing]] = Failure(java.lang.IllegalStateException: test) 

swap(None) 
// res2: scala.util.Try[Option[Nothing]] = Success(None) 
2

Die cats Bibliothek ermöglicht es Ihnen, Sequenz eine Option einen Try sehr leicht:

scala> import cats.implicits._ 
import cats.implicits._ 

scala> import scala.util.{Failure, Success, Try} 
import scala.util.{Failure, Success, Try} 

scala> Option(Success(1)).sequence[Try, Int] 
res0: scala.util.Try[Option[Int]] = Success(Some(1)) 

scala> Option(Failure[Int](new IllegalArgumentException("nonpositive integer"))).sequence[Try, Int] 
res1: scala.util.Try[Option[Int]] = Failure(java.lang.IllegalArgumentException: nonpositive integer) 

scala> None.sequence[Try, Int] 
res2: scala.util.Try[Option[Int]] = Success(None) 
Verwandte Themen