【问题标题】:Adding logging if return value is None如果返回值为 None,则添加日志记录
【发布时间】:2011-07-25 16:30:13
【问题描述】:
假设有两个函数findUser(id:String):Option[User]和findAddress(user:User):Option[Address]调用如下:
for(user
现在我想将错误记录添加到此for-comprehension。如果找不到user 或address,我想调用log(msg:String) 函数。
for(user
我可以在不更改函数签名的情况下这样做吗?
【问题讨论】:
标签:
scala
option
for-comprehension
【解决方案1】:
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 了解与您的问题相关的各种建议。
【解决方案2】:
也许
implicit def withIfNone[A](o: Option[A]) = new {
def ifNone(action: => Unit) = { if (o == None) action; o }
}
您也可以考虑使用 Either 而不是 option(或将您的选项转换为 Either)。这不适用于 foreach (a for without a yield),但你可能会这样做
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】:
这可能有点矫枉过正,但它看起来很像你想要的 ;)
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。