更好地处理嵌套选项

时间:2018-09-24 23:33:42

标签: scala

考虑一个嵌套结构,其中的相关属性如下:

case class Validation { sql: Option[SqlDataSource] }

case class SqlDataSource { dfh: Option[DataFrameHolder] }

case class DataFrameHolder { sql: Option[String] }

我目前正在使用的天真的方法是:

    val ssql = expVal.sql.getOrElse(
        vc.dfh.map(_.sql
          .getOrElse(throw new IllegalStateException(s"$logMsg CompareDF: Missing sql container"))
        ).getOrElse(throw new IllegalStateException(s"$logMsg CompareDF: dfh missing sql"))
      .sql.getOrElse(throw new IllegalStateException(s"$logMsg CompareDF: Missing sql")))

尽管这样做确实可以完成工作,但它对读者也不友好,对开发人员也不友好(很难正确地嵌套)。有什么更好的方法来解决这个问题吗?

更新谢谢您的出色回答-这将有助于清理并简化向前发展的异常处理代码。

4 个答案:

答案 0 :(得分:3)

您可能想使用cats库来使您的代码更具功能性。您可以将Option转换为Either,如下所示:

import cats.implicits._

 def toEither[T](s: Option[T], error: String) = {
    s.liftTo[Either[String, ?]](error)
  }

  def runEither = {

    val result =
      for {
        sqlDataSource   <- toEither(validation.sql, s"Missing sql container")
        dataFrameHolder <- toEither(sqlDataSource.dfh, s"dfh missing sql")
        sql             <- toEither(dataFrameHolder.sql, s"Missing sql")
      } yield sql
    result match {
      case Right(r) => r
      case Left(e)  => throw new Exception(e)
    }
  }

答案 1 :(得分:3)

我建议使用与Binzi Cao's answer非常相似的解决方案,但只能将标准库与scala.util.Try monad一起使用:

def toTry[T](x: Option[T], message: String): Try[T] =
  x.map(Success(_)).getOrElse(Failure(new IllegalStateException(message)))

(for {
  sqlDataSource   <- toTry(validation.sql, s"Missing sql container")
  dataFrameHolder <- toTry(sqlDataSource.dfh, s"dfh missing sql")
  sql             <- toTry(dataFrameHolder.sql, s"Missing sql")
} yield sql)
.get

理解力产生Try。如果我是.get,则在产生的Try上应用Try会返回String的内容(dataFrameHolder中的Success[String]),或者抛出如果是Failure[IllegalStateException],则为例外。

答案 2 :(得分:3)

Luis MiguelMejíaSuárez和Xavier Guihot的回答都很好,但是不需要构建自己的toTry()方法。 Either已经提供了一个,并且由于Either也具有右偏,因此可以用于理解。

import util.Try

val ssql: Try[String] = (for {
  ql  <- expVal.ql.toRight(new IllegalStateException("yada-yada"))
  dfh <- ql.dfh   .toRight(new IllegalStateException("yoda-yoda"))
  sql <- dfh.sql  .toRight(new IllegalStateException("yeah-yeah"))
} yield sql).toTry

答案 3 :(得分:2)

如果您想要快速语义失败,我将for comprehensionj一起使用。

Try