【问题标题】: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。如果找不到useraddress,我想调用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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-31
          • 2014-02-15
          • 2021-07-29
          • 2020-04-16
          • 1970-01-01
          相关资源
          最近更新 更多