2011-11-11 8 views
10

Potrzebuję zainicjować zestaw vals, gdzie kod do ich inicjowania może rzucić wyjątek. Chciałbym napisać:Inicjowanie vals, które mogą rzucić wyjątek

try { 
    val x = ... generate x value ... 
    val y = ... generate y value ... 
} catch { ... exception handling ... } 

... use x and y ... 

Ale to (oczywiście) nie działa, ponieważ x i y nie znajdują się poza próbą.

Łatwo rozwiązać problem za pomocą zmiennych Zmienna:

var x: Whatever = _ 
var y: Whatever = _ 
try { 
    x = ... generate x value ... 
    y = ... generate y value ... 
} catch { ... exception handling ... } 

... use x and y ... 

Ale to nie jest dokładnie to bardzo miłe.

Jest to także łatwy do rozwiązania problemu przez powielenie obsługę wyjątków:

val x = try { ... generate x value ... } catch { ... exception handling ... } 
val y = try { ... generate y value ... } catch { ... exception handling ... } 

... use x and y ... 

Ale to wymaga powielenie obsługę wyjątków.

Musi być "miły" sposób, ale umyka mi.

+1

Być może wykorzystujesz fakt, że leniwe vale przeliczają swoją wartość przy następnym dostępie, jeśli wyjątek zostanie zgłoszony podczas ich inicjowania? – soc

Odpowiedz

5

Prostym rozwiązaniem byłoby zdefiniowanie funkcji owijki, która wykorzystuje parametry nazwy-nazwy.

def safely[T](f: => T): T = try { f } catch { /* exception handling */ } 
// You'll have to play around with safely's type signature, depending on what 
// you do in the exception handling 
val x = safely { generateX } 
val y = safely { generateY } 

Lub, jeśli czujesz się naprawdę szarmancko, Scala 2.9 umożliwia użycie funkcji częściowej jako wyjątku.

val handler: PartialFunction[Throwable, Unit] = { /* exception handling */ } 
val x = try { generateX } catch handler 
val y = try { generateY } catch handler 

W sumie chciałbym powiedzieć, że pierwsza metoda jest najprostsza. Ale jeśli możesz napisać wielokrotnego użytku bity obsługi wyjątków, które mogą być skomponowane razem przy użyciu orElse lub andThen, wówczas druga metoda byłaby bardziej odpowiednia.

9

Co powiesz na dopasowywanie wzorców?

val (x, y) = try generateX -> generateY catch { /*exception handling*/ } 

lub

val (x, y) = try (generateX, generateY) catch { /*exception handling*/ } 
+0

Nie potrzebujesz 'Some'. –

+0

Thx, naprawiono ... – agilesteel

+2

Jest to jedna z tych sytuacji, w których chciałbym pozwolić na zaakceptowanie wielu odpowiedzi. Zaakceptowałem odpowiedź Dave'a, ponieważ jest ona najbliższa temu, co wykorzystałem, ale wszystkie z nich są dobrym podejściem. Dzięki! –

7

agilesteel za odpowiedź jest w porządku, jeśli chcesz po prostu złapać żadnego wyjątku, który jest wrzucony i zrobić coś proceduralnej w bloku catch. Jednak możesz chcieć poradzić sobie z wyjątkami osobno w późniejszym czasie, w takim przypadku możesz rozważyć wprowadzenie swoich typów jako Option lub Either.

Wbudowany sposób, aby to zrobić, to obiekt Catch. Zobacz Exception docs.

Sposób korzystania z niego zależy od tego, co ma się stać, gdy wystąpi wyjątek. Na przykład

import util.control.Exception.allCatch 

def handleInfinities(n: Int) = { 
    val x = allCatch.either { 100/n }  // Either[Throwable, Int] 
    val y = allCatch.either { 100/(n - 1) } 

    Seq(x, y) map { case Left(_) => Int.MaxValue; case Right(z) => z } 
} 

Następnie handleInfinities(1) daje

Seq[Int] = List(100, 2147483647) 

zauważyć, jak przypisania zmiennych i obsługa wyjątków są teraz całkowicie oddzielne.

+0

Jest to jedna z tych sytuacji, w których chciałbym pozwolić na zaakceptowanie wielu odpowiedzi. Zaakceptowałem odpowiedź Dave'a, ponieważ jest ona najbliższa temu, co wykorzystałem, ale wszystkie z nich są dobrym podejściem. Dzięki! –

1
import util.control.Exception._ 
def handler[A]: Catch[A] = handling(classOf[Exception]) by exceptionHandlingFunc 
val x = handler[X] apply { generateX } 
val y = handler[Y] apply { generateY } 
import util.control.Exception._ 
def handler[A]: Catch[A] = handling(classOf[Exception]) by exceptionHandlingFunc 
val x = handler[X] apply { generateX } 
val y = handler[Y] apply { generateY } 
Powiązane problemy