2010-09-10 6 views
5

scrivo una serie di semplici script Scala che finiscono a partire da un semplice fiammifero modello su args come:Pattern Match args e dare messaggi di errore in uno script leggero Scala

val Array(path, foo, whatever) = args 
// .. rest of the script uses "path", "foo", etc. 

Naturalmente, se fornisco il numero errato di argomenti, ricevo un errore imperscrutabile come:

scala.MatchError: [Ljava.lang.String;@7786df0f 
    at Main$$anon$1.<init>(FollowUsers.scala:5) 
    ... 

C'è un modo semplice per dare un messaggio di errore più utile? La mia soluzione attuale è quella di fare qualcosa di simile:

args match { 
    case Array(path, foo, whatever) => someFunction(path, foo, whatever) 
    case _ => System.err.println("usage: path foo whatever") 
} 
def someFunction(path: String, foo: String, whatever: String) = { 
    // .. rest of the script uses "path", "foo", etc. 
} 

Ma che si sente come un sacco di boilerplate quello che con dover definire tutta una altra funzione, e di dover ripetere "percorso", "pippo" e "qualunque" in così tanti posti. C'è un modo migliore? Immagino che potrei perdere la funzione e mettere il corpo nella dichiarazione della partita, ma mi sembra meno leggibile.

So che potrei usare uno dei tanti argomenti della riga di comando che analizzano i pacchetti, ma sto davvero cercando qualcosa di estremamente leggero che non debba aggiungere una dipendenza e modificare il mio classpath per.

risposta

3

Che ne dici?

val Array(path, foo, whatever) = if (args.length == 3) args 
    else throw new Exception("usage:path foo whatever") 

== modifica ==

sulla base di commento di Randall:

require(args.length == 3, "usage: path foo whatever") 
val Array(path, foo, whatever) = args 

Questo è boilerplate minimo. I tuoi val sono di portata, non devi occuparti della parentesi di chiusura e ricevi il messaggio di errore di utilizzo.

+0

Sì, immagino sia ok, anche se otterrai una traccia di stack invece di un semplice messaggio di errore. – Steve

+0

Questo è ciò per cui 'require' è destinato. Per esempio. 'require (args.length == 3," args deve avere la lunghezza tre in chiamata a XYZ ")' –

+0

La versione con "require" è carina e semplice. Si ottiene comunque un'eccezione molto prolissa: 'java.lang.IllegalArgumentException: requisito non riuscito: usage: path foo whatever' (e quindi tutto il solito traceback). Ha perfettamente senso per uno sviluppatore Scala, ma potrebbe essere un po 'di confusione per qualcuno che non conosce Scala ma vuole solo usare il mio script. – Steve

1

Un modo è quello di catturare MatchError:

try { 
    val Array(path, foo, whatever) = args 
} catch { 
    case _: MatchError => System.err.println("usage: path foo whatever") 
} 
+0

Ma dopo "try/catch", "path", "foo" e "whatever" saranno fuori portata. Quindi dovrai fare praticamente la stessa cosa del codice sopra - aggiungere una funzione ausiliaria o definire l'intero metodo principale nel blocco try. – Steve

3
scala> val args = Array("evil", "mad", "scientist") 
args: Array[java.lang.String] = Array(evil, mad, scientist) 

scala> def logToConsole(th: Throwable) { Console.err.println("Usage: path foo bar") } 
logToConsole: (th: Throwable)Unit 

scala> handling(classOf[MatchError]) by logToConsole apply { 
    | val Array(path, foo, bar) = args 
    | println(path) 
    | } 
evil 

scala> handling(classOf[MatchError]) by logToConsole apply { 
    | val Array(path, foo, bar) = Array("#fail") 
    | println(path) 
    | } 
Usage: path foo bar 
+1

Sì, mi è appena venuto in mente la stessa cosa. Lo svantaggio di questo approccio è che se qualcos'altro nello script genera un errore MatchError, il gestore lo farà apparire come se gli argomenti della riga di comando fossero sbagliati, nascondendo l'errore di corrispondenza reale. – Steve

0

mi ha colpito che forse la nuova util.control.Exception potrebbe avere una soluzione:

import scala.util.control.Exception 

Exception.handling(classOf[scala.MatchError]).by{ 
    e => System.err.println("usage: path foo whatever") 
} { 
    val Array(path, foo, whatever) = args 
    // .. rest of the script uses "path", "foo", etc. 
} 

Questo almeno mette l'errore gestendo prima e tenendo insieme il resto del codice, anche se mi rende un po 'nervoso avere un blocco try così grande (quel secondo blocco con la corrispondenza del pattern Array è essenzialmente tutto nello stesso blocco try che ha ndled da Exception.handling).

EDIT: Sembra che Miss Faktor abbia pubblicato circa la stessa cosa, ma con una funzione definita esplicitamente e una chiamata esplicita da applicare.

Problemi correlati