2011-04-20 64 views
28

我最近看到代碼:這樣斯卡拉醒目混亂

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

這是什麼opt?一個選項?爲什麼不使用getOrElse來提取值?在上面的代碼中,如果NumberFormatException被拋出,maybeInt將爲None嗎?

+0

嘿,那個代碼很熟悉! :-) – 2011-04-20 22:38:59

+0

我會想象如此:) – Geo 2011-04-21 06:27:27

回答

34

catching看起來像是某種方法調用,不是嗎?它是,但實際上它返回一個類Catch的實例;它不直接採取論據。這個類有兩個方法對處理異常特別有用(還有幾個方法用於捕獲多個異常)。首先是

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

其正在這裏使用 - 你給它的東西,可能會拋出異常,它將返回Some(result),如果一切正常,並None如果目標異常被抓住了:

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) 

然後,您可以使用mapfiltergetOrElse或其他用於處理選項的其他方式處理此問題。

其他有用的方法是either,如果有異常被拋出,返回的Left(exception)一個實例,一個Right(result)如果不是:

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) 

然後可以使用fold或映射到一個選項或什麼否則你喜歡和他人一起做。

注意,您可以定義一個捕手和多次使用(這樣你就不會需要創建捕手對象,你每一次,例如,解析一個整數):

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 

編輯:正如丹尼爾在評論中指出的,這仍然會創建一個臨時的Catch[Option];在給定方法簽名的情況下,並不是簡單的方法來讓它捕獲異常並生成選項而不創建任何額外的對象。這讓我想起我爲什麼要寫自己的方法來做到這點:

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

感謝雷克斯!我會把這個好用:) – Geo 2011-04-20 20:18:10

+0

這真的很方便。不知道它存在。感謝您的寫作。 – overthink 2011-04-20 20:22:09

+6

實際上,'catching'不會返回'Catch [NFE]',而是'Catch [Nothing]'。類型參數或「Catch」指示在異常情況下它可能返回的內容。例如,'withApply'接受一個函數'Throwable => U',並返回一個'Catch [U]'。 'opt'方法將首先使用'toOption'來獲得'Catch [Option [X]]',如果拋出異常,則返回'None',然後將'Some(body)'傳遞給該捕獲器。 – 2011-04-20 22:52:27

0

我用一種更簡單的模式時,只有一個陷阱:

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

我絕對沒有Scala的親,我想你可以找到更短的東西