2010-09-10 7 views
5

escribo una serie de guiones Scala simples que terminan a partir de un simple ajuste de patrones en args como:args coincidencia de patrones y dar mensajes de error en un script ligero Scala

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

Por supuesto, si yo proporciono la número incorrecto de argumentos, me sale un error inescrutable como:

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

¿hay una manera fácil de dar un mensaje de error más útil? Mi solución actual es hacer algo como:

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

Pero que se siente como un montón de repetitivo lo de tener que definir una otra función entera, y tener que repetir "camino", "foo" y "lo que" en tantos lugares ¿Hay una mejor manera? Supongo que podría perder la función y poner el cuerpo en la declaración del partido, pero eso me parece menos legible.

Sé que podría utilizar uno de los muchos paquetes de análisis de argumentos de línea de comandos, pero realmente estoy buscando algo extremadamente liviano que no tenga que agregar una dependencia y modificar mi classpath.

Respuesta

3

¿Qué tal?

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

== == editar

basado en el comentario de Randall:

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

Eso es repetitivo mínimo. Sus valores están dentro del alcance, no tiene que lidiar con el corsé de cierre y recibe el mensaje de error de uso.

+0

Sí, creo que está bien, aunque obtendrá un seguimiento de pila en lugar de un mensaje de error directo. – Steve

+0

Esto es para lo que 'requiere '. P.ej. 'require (args.length == 3," args debe tener una longitud tres en la llamada a XYZ ")' –

+0

La versión con "require" es agradable y simple. Sin embargo, obtienes una excepción muy detallada con eso: 'java.lang.IllegalArgumentException: requisito fallido: usage: path foo whatever' (y luego todo el traceback habitual). Tiene mucho sentido para un desarrollador de Scala, pero puede ser un poco confuso para alguien que no conoce a Scala pero que solo quiere usar mi script. – Steve

1

Una forma es coger MatchError:

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

Pero luego "ruta", "foo" y "lo que sea" quedarán fuera del alcance después de la prueba/captura. Por lo tanto, tendrá que hacer básicamente lo mismo que el código anterior: agregue una función auxiliar o defina todo el método principal en el bloque 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í, solo se me ocurrió lo mismo. La desventaja de este enfoque es que si algo más en el script arroja un MatchError, el controlador hará que parezca que los argumentos de la línea de comando fueron incorrectos, ocultando el error de coincidencia real. – Steve

0

me ocurrió que tal vez el nuevo util.control.Exception podría tener una solución:

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

Esto, al menos, pone el error manejar primero y mantener el resto del código juntos, aunque me pone un poco nervioso tener un bloque de intentos tan grande (ese segundo bloque con la coincidencia de patrones Array está esencialmente en el mismo bloque try que está encontrado por Exception.handling).

EDIT: Parece que Missing Faktor publicó sobre la misma cosa también, pero con una función explícitamente definida y una llamada explícita a aplicar.

Cuestiones relacionadas