如何删除该选项,使其仅为Try[Int]
而非Try[Option[Int]]
?
val m = Map("a" -> "1a", "b" -> "2")
Try(m.get("a").map(_.trim.toInt))
>>es17: scala.util.Try[Option[Int]] = Failure(java.lang.NumberFormatException: For input string: "1a")
答案 0 :(得分:7)
Map#get
会返回Option[String]
,但在这种情况下,您可以使用Map#apply
代替String
。
scala> Try(m("a").trim.toInt)
res3: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "1a")
scala> Try(m("b").trim.toInt)
res4: scala.util.Try[Int] = Success(2)
如果您要查找的密钥不存在, apply
会抛出异常,但无论如何Try
都会抓住它。
答案 1 :(得分:1)
这个答案更详细地说明了评论:
我想知道是否有办法使用flapmap?您的解决方案适合我,只想了解其他替代方案。
正如您可能听到的那样,Option
和Try
是monad实例,而monad可以方便地表示计算序列,但它们不会与其他monad组合。换句话说,我们无法撰写Option
和Try
。我们需要找到一个共同点。
Option
和Try
之间的语义差异在于Try
包含有关结果不存在时的情况的信息。
我们可以使用Try
从Option
转到Try#toOption
,有效地删除我们可能遇到的任何失败信息。
如果我们想要反过来,我们需要添加这些信息:当Option
中没有值时,需要提供失败原因。像这样:
import scala.util.{Try, Success, Failure}
def optionToTry[T](opt:Option[T], failure: => Throwable): Try[T] = opt match {
case Some(v) => Success(v)
case None => Failure(failure)
}
在该函数的帮助下,我们可以将原始表达式重写为:
val res: Try[Int] = for {
strValue <- optionToTry(m.get("a"), new NoSuchElementException("a"))
value <- Try(strValue.trim.toInt)
} yield value
在后台使用flatMap
组成这两个Try
个实例:
val res = optionToTry(m.get("a"), new NoSuchElementException("a"))
.flatMap(strValue => Try(strValue.trim.toInt))
请注意,我们可以使用不安全的地图getter来节省一些编码:
val res: Try[Int] = for {
strValue <- Try(m("a"))
value <- Try(strValue.trim.toInt)
} yield value
但考虑到在JVM中处理异常的成本,这个版本的计算成本会更高。