29 votes

Confusion dans les captures Scala

J'ai récemment vu un code comme celui-ci :

val maybeInt = catching(classOf[NFE]) opt arg.toInt

Qu'est-ce que c'est ? opt ? Une option ? Pourquoi n'utilise-t-il pas getOrElse pour extraire la valeur ? Dans le code ci-dessus, est-ce que maybeInt être None si une NumberFormatException est levée ?

36voto

Rex Kerr Points 94401

catching on dirait que c'est une sorte d'appel de méthode, n'est-ce pas ? C'est le cas, mais il renvoie en fait une instance de la classe Catch ; elle ne prend pas directement un argument. Cette classe possède deux méthodes qui sont particulièrement utiles pour traiter les exceptions (et plusieurs autres pour attraper des exceptions multiples). La première est

def opt [U >: T] (body: ⇒ U) : Option[U]

qui est utilisé ici - vous lui donnez quelque chose qui peut lancer une exception, et il retournera Some(result) si tout s'est bien passé, et None si l'exception ciblée a été attrapée :

scala> type NFE = NumberFormatException
defined type alias NFE

scala> import scala.util.control.Exception._
import scala.util.control.Exception._

scala> catching(classOf[NFE]).opt( "fish".toInt )
res0: Option[Int] = None

scala> catching(classOf[NFE]).opt( "42".toInt )  
res1: Option[Int] = Some(42)

Vous pouvez alors traiter cette question avec map o filter o getOrElse ou tout autre moyen que vous utilisez pour traiter les options.

L'autre méthode utile est either qui renvoie une instance de Left(exception) si une exception a été levée, et un Right(result) si elle ne l'était pas :

scala> catching(classOf[NFE]).either( "fish".toInt )
res2: Either[Throwable,Int] = Left(java.lang.NumberFormatException: For input string: "fish")

scala> catching(classOf[NFE]).either( "42".toInt )
res3: Either[Throwable,Int] = Right(42)

Vous pouvez alors utiliser fold ou le mapper à une option ou tout ce que vous aimez faire avec l'un ou l'autre.

Notez que vous pouvez définir un seul attrapeur et l'utiliser plusieurs fois (vous n'avez donc pas besoin de créer l'objet attrapeur à chaque fois que vous analysez un entier, par exemple) :

scala> val catcher = catching(classOf[NFE])
catcher: util.control.Exception.Catch[Nothing] = Catch(java.lang.NumberFormatException)

scala> catcher.opt("42".toInt)
res4: Option[Int] = Some(42)

scala> catcher.opt("fish".toInt)
res5: Option[Int] = None

Edit : comme Daniel le fait remarquer dans les commentaires, cela crée toujours un problème temporaire. Catch[Option] Étant donné les signatures des méthodes, il n'y a pas de moyen facile de faire en sorte qu'elles détectent les exceptions et génèrent des options sans créer d'objets supplémentaires. Cela me rappelle pourquoi j'écris mes propres méthodes pour faire exactement cela :

def optNFE[T](t: => T) = try { Some(t) } catch {case nfe: NFE => None}
optNFE( "fish".toInt )  // gives None
optNFE( "42".toInt ) // gives Some(42)

1voto

Nicolas Zozol Points 1514

J'utilise un motif plus simple lorsqu'il n'y a qu'une seule prise :

 try{
      return args.split(" ").exists(line.startsWith _)
 }catch {
    case _ =>{//generic exception
      logger.error("Error with line ${line} for ${ex.message}")
      throw _
    }    
 }

Je ne suis certainement pas encore un pro de Scala, et je suppose que vous pourriez trouver des trucs plus courts

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X