Scala 处理选项和从 Scala Map 抛出异常的最优雅的方式

标签 scala dictionary scala-option

我有一张 map ,想要:

  • 检索值而不处理选项
  • 当没有这样的 key 时记录一条消息。
  • 当键不存在时,返回一个默认值(除了记录一条消息)很好。这是可选的,因为当代码在这里失败时,它不应该继续。

  • 我有几种方法可以做到
    val map: Map[String, Int] // defined as such for simplification
    
    // 1 short but confusing with error handling
    def getValue(key: String): Int = {
        map.getOrElse(key, scala.sys.error(s"No key '$key' found"))
    }
    
    // in case you don't know scala.sys.error 
    package object sys {
     def error(message: String): Nothing = throw new RuntimeException(message)
    }
    
    // 2 verbose
    def getValue(key: String): Int = {
        try {
          map(key)
        } catch {
          case _: Throwable => scala.sys.error(s"No key '$key' found")
        }
    }
    
    // 3 Try and pattern matching
    import scala.util.{Failure, Success, Try}
    
    def getValue(key: String): Int = {
        Try(map(key)) match{
          case Success(value) => value
          case Failure(ex) => sys.error(s"No key '$key' found ${ex.getMessage}")
        }
    }
    

    欢迎其他解决方案。
    我正在寻找简洁而不神秘。使用标准 Scala(不需要 Scalaz、Shapeless ...)

    灵感:
  • https://alvinalexander.com/scala/how-to-access-map-values-getorelse-scala-cookbook
  • http://danielwestheide.com/blog/2012/12/26/the-neophytes-guide-to-scala-part-6-error-handling-with-try.html
  • 最佳答案

    抛出错误的最优雅的方法是您的 (1):
    map.getOrElse(key, throw /* some Exception */)
    不应使用第二个和第三个选项:您知道可能发生的实际错误: map 不包含 key 。因此,将其包装在 try 或 Try 中是不必要的工作。
    最糟糕的是,它会捕获其他不应该出现的异常。特别是不应捕获的致命异常。

    但是,管理异常的真正最优雅的方式 在 scala 中实际上是用类型跟踪它们。

    一个简单的通用方法(但有时过于通用)是使用 Try。一旦您的代码可能失败,所有内容都包含在 Try 中,然后在 map 和 flatMap 中调用代码(您可以使用 for-comprehension 使其更具可读性)

    更具体的方法是使用(来自 scala)或 \/来自 scalaz 并明确您正在管理的错误类型,例如 \/(MissingData, String)一些 MissingData你所做的课。例如:

    import scalaz.\/
    import scalaz.syntax.either._
    
    sealed trait KnownException
    case class MissingData(message: String) extends KnownException
    
    // type alias used for readability
    type Result[A] = \/[KnownException, A]
    
    // retrieve a param, or a MissingData instance
    def getParam(param: Map[String, Int], key: String): Result[Int] = param.get(key) match {
      case None => MissingData(s"no param for key $key").left
      case Some(v) => v.right
    }
    
    // example on how to combine multiple \/
    // using for-comprehension
    def computeAPlusB(param: Map[String, Int]): Result[Int] = for {
      paramA <- getParam(param, "a")
      paramB <- getParam(param, "b")
    } yield paramA + paramB
    

    关于Scala 处理选项和从 Scala Map 抛出异常的最优雅的方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49254811/

    相关文章:

    Scala - 定义范围内数字的类型

    scala - 运行SBT runTask时如何访问资源?

    Scala 类型边界与 Foo[_]

    Scala 赋值与引用类型

    python - 从具有元组值的字典中选择特定元素

    java - 如何让 entrySet() 在新行显示键值对?(java)

    java - Java 中的正则表达式映射实现

    Scala 选项类型未按预期推断

    scala - 为什么Option没有折叠方法?

    scala - Scala 中的延迟合并选项