2014-04-01 76 views
3

我正在查看以下代碼段。當代碼中map-getOrElse和嵌套的patten匹配增加時,它看起來不那麼優雅。你有什麼更好的選擇建議?使代碼在功能上更具可讀性

case MyMessage => 
     val image = (request \ "image").asOpt[String] 
     image.map { im => 
      val conf = (request \ "confirmation").asOpt[String] 
      conf.map { cf => 
      //code to retrieve ride 

      ride match { 
       case Some(r) => 
       if (booleanCondition) sender ! SuccessCommand(JsBoolean(true), command) 
       else sender ! FailureCommand("Problem updating", command) 
       case None => sender ! FailureCommand("Ride empty", command) 
      } 

      } getOrElse (sender ! FailureCommand("Missing number", command)) 

     } getOrElse (sender ! FailureCommand("Missing image", command)) 
+2

你有'發件人! FailureCommand'四次。也許'def reportFailure(msg:String)=發件人! FailureCommand(msg,command)'在適當的位置(即'sender'和'command'在範圍內)? –

回答

2

每當你映射了與產生選項的功能選項,你應該考慮是否應該使用flatMap

def f(x: Int): Option[Int] = Some(x + 1) 

f(1).flatMap(x => f(x)).flatMap(y => f(y))    // Some(4) 
f(1).flatMap(x => f(x)).flatMap(y => f(y)).getOrElse(0) // 4 

您也可以使用,推導了這一點,這是非常好的具有乾淨的代碼,當你有這些長鏈:

(for(x <- f(1); y <- f(x); z <- f(y)) yield z).getOrElse(0) 
+0

謝謝@dhg。我想知道如何從理解的角度來表示原始片段,特別是那些發件人!消息調用,對於每個失敗/ getOrElse情況都不同? – user2066049

1

我想你應該能夠有很多的這個塌陷到Option.fold(),大致如下:

case MyMessage => 
    sender ! 
    getImage().fold(fail("Missing image")) { im => 
     getConf().fold(fail("Missing number")) { conf => // conf isn't used 
     getRide().fold(fail("Ride empty")) { r => 
      if (booleanCondition) succeed(true) 
      else fail("Problem updating") 
     } 
     } 
    } 

這接通了一點比在這種情況下flatMaporElse更簡潔(見下文)

Option.fold(ifEmpty){f}返回ifEmpty(懶惰地評估),如果選項是空的,或求值如果選項已滿,則功能f

上面的代碼假定您創建幫助函數來獲取各種選項(或者您可以內聯相關的代碼)。它還假定您將創建的命令提取到一個或兩個輔助函數中,以避免重複引用command

爲了比較,使用flatMap一個解決方案看起來是這樣的:

case MyMessage => 
    sender ! 
    getImage().flatMap { im => 
     getConf().flatMap { conf => 
     getRide().flatMap { r => 
      if (booleanCondition) Some(succeed(true)) 
      else Some(fail("Problem updating")) 
     }.orElse(Some(fail("Ride Empty"))) 
     }.orElse(Some(fail("Missing number"))) 
    }.getOrElse(fail("Missing image")) 

,你可以通過使(failsucceed)返回Some[Command]而不是Command

2

您的輔助方法的變體非常輕微縮短解決此問題的另一種方法是從各種幫助功能返回Either[Command,String],而不是Option。然後,這將允許您使用for理解,類似如下:

val result = for { 
    i <- getImage().right 
    c <- getConf().right 
    r <- getRide().right 
    z <- check(r).right 
} yield z 

// extract either left or right, whichever is occupied 
sender ! result.fold(identity, _ => success()) 

這所期望的特性,我們只要我們遇到錯誤停止,捕捉特定的錯誤 - 或繼續成功結論。