2011-11-11 12 views
10

Devo inizializzare un set di vals, in cui il codice per inizializzarli potrebbe generare un'eccezione. Mi piacerebbe scrivere:Inizializzazione di vals che potrebbero generare un'eccezione

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

... use x and y ... 

Ma questo (ovviamente) non funziona perché xey non sono portata al di fuori della prova.

E 'facile risolvere il problema utilizzando le variabili mutabili:

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

... use x and y ... 

Ma non è esattamente molto bello.

E 'anche facile da risolvere il problema duplicando il gestione delle eccezioni:

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

... use x and y ... 

Ma che coinvolge duplicare il gestione delle eccezioni.

Ci deve essere un modo "carino", ma mi sfugge.

+1

Forse si sfrutta il fatto che i valori lazy valgono il loro valore all'accesso successivo se viene generata un'eccezione durante l'inizializzazione? – soc

risposta

5

Una soluzione semplice sarebbe quella di definire una funzione wrapper che utilizza i parametri del nome.

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 } 

Oppure, se ti senti davvero ricercata, Scala 2.9 permette una funzione parziale da utilizzare come gestore di eccezioni.

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

Nel complesso, direi che il primo metodo è il più semplice. Ma se puoi scrivere bit riutilizzabili di gestori di eccezioni che possono essere composti insieme usando orElse o andThen, il secondo metodo sarebbe più appropriato.

9

E per quanto riguarda la corrispondenza del modello?

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

o

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

Non è necessario il 'Some'. –

+0

Thx, risolto ... – agilesteel

+2

Questa è una di quelle situazioni in cui desidero consentire a più risposte accettate. Ho accettato la risposta di Dave, poiché è la cosa più vicina a quello che ho finito con l'utilizzo, ma tutti questi sono buoni approcci. Grazie! –

7

risposta di agilesteel va bene se si desidera solo per catturare qualsiasi eccezione che è generata e fare qualcosa procedurale nel blocco catch. Tuttavia potresti voler gestire le eccezioni singolarmente in un secondo momento, nel qual caso potresti prendere in considerazione di rendere i tuoi tipi uno Option o Either.

Un modo incorporato per farlo è con un oggetto Catch. Vedi lo Exception docs.

Il modo in cui lo si utilizza dipenderà da ciò che si desidera che si verifichi quando si verifica un'eccezione. Per esempio

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 } 
} 

Poi handleInfinities(1)

Seq[Int] = List(100, 2147483647) 

Notate come le assegnazioni delle variabili e la gestione di eccezioni sono ormai completamente separati.

+0

Questa è una di quelle situazioni in cui vorrei che SO accettasse più risposte. Ho accettato la risposta di Dave, poiché è la cosa più vicina a quello che ho finito con l'utilizzo, ma tutti questi sono buoni approcci. Grazie! –

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 } 
Problemi correlati