2011-07-25 14 views
2

假設有兩個功能findUser(id:String):Option[User]findAddress(user:User):Option[Address]援引如下:添加記錄,如果返回值是無

for(user <- findUser(id); address <- findAddress(user)) println(address)

現在我想的錯誤記錄添加到這個for-comprehension。如果找不到useraddress,我想調用log(msg:String)函數。

for(user <- findUser(id) ifNone log("user not found"); 
    address <- findAddress(user) ifNone log("address not found")) 
     println(address)

我可以在不更改功能簽名的情況下做到嗎?

回答

1

也許

implicit def withIfNone[A](o: Option[A]) = new { 
    def ifNone(action: => Unit) = { if (o == None) action; o } 
} 

您也可以考慮使用以下任一替代選項(或轉換你的選擇要麼)。這將不是一個foreach(一種無產量)工作,但你可能會做

for(
    a <- option1.toRight("option1 missing").right; 
    b <- option2.toRight("option2 missing").right) 
yield f(a,b) 

然後你就可以在結果模式匹配

case Left(error) => log (error) 
case Right(result) => // use result 
3

電梯的Box是一個更合適的類你的使用案例。 A Box就像Option,但有兩個空狀態:ok和錯誤。你可以這樣使用它:

val addr = for { 
    user <- findUser(id) ?~ "user not found" 
    address <- findAddress(user) ?~ "address not found" 
} yield address 

address match { 
    case Full(addr) => println(addr) 
    case oops: Failure => println(oops.msg) // see Failure for more details 
} 

請參閱this blog瞭解與您的問題相關的各種建議。如果你不知道什麼剛好讀this想法)

object Extensions { 
    // You need a wrapper since Option is sealed 
    class OptionWrapper[E](option: Option[E]) { 
    def foreach[U](f: E => U) { 
     option foreach f 
    } 
    def isEmpty = option.isEmpty 
    } 

    // Modification trait for OptionWrapper 
    trait ErrorLogging[E] extends OptionWrapper[E] { 
    abstract override def foreach[U](f: E => U) { 
     if (isEmpty) 
     println("error") 
     else 
     super.foreach(f) 
    } 
    } 

    // Accessor for the new mixin 
    def log[E](option: Option[E]) = new OptionWrapper(option) with ErrorLogging[E] 
} 

object TestingLogger extends App { 
    case class User(address: String) 
    def findUser(id: Int): Option[User] = if (id == 1) Some(User("address")) else None 
    def findAddress(user: User): Option[String] = Some(user.address) 

    import Extensions._ 

    for { 
    user <- log(findUser(1)) // prints out address 
    address <- log(findAddress(user)) 
    } println(address) 

    for { 
    user <- log(findUser(2)) // prints out error 
    address <- log(findAddress(user)) 
    } println(address) 
} 

;

1

這可能是矯枉過正,但它看起來很像你想要的東西。