如果返回值为None,则添加日志记录

时间:2011-07-25 16:30:14

标签: scala option for-comprehension

假设有两个函数findUser(id:String):Option[User]findAddress(user:User):Option[Address]被调用如下:

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

现在我想将错误记录添加到此for-comprehension。如果找不到log(msg:String)user,我想调用address函数。

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

我可以不改变功能签名吗?

3 个答案:

答案 0 :(得分:3)

Lift Box更适合您的使用案例。 Box就像Option,但有两个空状态:ok和error。您可以像这样使用它:

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

答案 1 :(得分:1)

也许

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

您也可以考虑使用Either而不是选项(或将选项转换为Either)。这不适用于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

答案 2 :(得分:1)

这可能是一种矫枉过正,但它看起来非常像你想要的;)

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

如果您不知道刚刚发生了什么,请阅读this