scala 我如何(最好)将选项转换为尝试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17521709/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I (best) convert an Option into a Try?
提问by Shadowlands
How can I (best) convert an Option returned by a method call into a Try (by preference, although an Either or a scalaz \/or even a Validation might be OK) including specifying a Failure value if appropriate?
我怎样才能(最好)将方法调用返回的 Option 转换为 Try(根据偏好,尽管可以使用任何一个或 scalaz\/甚至验证),包括在适当的情况下指定失败值?
For example, I have the following code, which feels kludgy, but does at least do (most of) the job:
例如,我有以下代码,感觉很笨拙,但至少可以完成(大部分)工作:
import scala.util._
case class ARef(value: String)
case class BRef(value: String)
case class A(ref: ARef, bRef: BRef)
class MismatchException(msg: String) extends RuntimeException(msg)
trait MyTry {
// Given:
val validBRefs: List[BRef]
// Want to go from an Option[A] (obtained, eg., via a function call passing a provided ARef)
// to a Try[BRef], where the b-ref needs to be checked against the above list of BRefs or fail:
def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {
val abRef = for {
a <- get[A](aRef) // Some function that returns an Option[A]
abRef = a.bRef
_ <- validBRefs.find(_ == abRef)
} yield (abRef)
abRef match {
case Some(bRef) => Success(bRef)
case None => Failure(new MismatchException("No B found matching A's B-ref"))
}
}
}
It feels like there should be a way for the final match to be morphed into a map or flatMap or similar construct and incorporated into the preceeding for comprehension.
感觉应该有一种方法可以将最终匹配变成 map 或 flatMap 或类似的构造,并合并到前面的理解中。
Also, I would prefer to be able to specify a different failure message if the call to return an Option[A] from the ARef failed (returned None) compared to the BRef check failing (I only care about knowing one reason for the failure, so a scalaz Validation doesn't feel like the ideal fit).
此外,与 BRef 检查失败相比,如果从 ARef 返回 Option[A] 的调用失败(返回 None),我希望能够指定不同的失败消息(我只关心知道失败的一个原因,所以scalaz Validation 感觉不像是最合适的)。
Is this a suitable place to use a monad transformer? If so, does scalaz provide a suitable one, or can someone give an example of what it would look like?
这是一个适合使用 monad 变压器的地方吗?如果是这样,scalaz 是否提供了一个合适的,或者有人可以举一个例子来说明它会是什么样子?
采纳答案by cmbaxter
If you start out with a Tryfrom the get go with your for-comp then you can eliminate the match at the end. You can do this by forcing the Optionto a Tryvia fold. Here's what that could look like:
如果你从一开始就用Try你的 for-comp 开始,那么你可以在最后消除比赛。您可以通过强制Option使用Tryvia来做到这一点fold。这可能是这样的:
def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {
for {
a <- get[A](aRef).fold[Try[A]](Failure[A](new OtherException("Invalid aRef supplied")))(Success(_))
abRef = a.bRef
_ <- validBRefs.find(_ == abRef).fold[Try[BRef]](Failure(new MismatchException("No B found matching A's B-ref")))(Success(_))
} yield abRef
}
With this approach, you can get different exceptions for the two different checks. It's not perfect, but maybe it will work for you.
使用这种方法,您可以获得两种不同检查的不同异常。它并不完美,但也许它对你有用。
回答by JasonG
You can use an implicit conversion
您可以使用隐式转换
implicit class OptionOps[A](opt: Option[A]) {
def toTry(msg: String): Try[A] = {
opt
.map(Success(_))
.getOrElse(Failure(new NoSuchElementException(msg)))
}
}
Scala standard lib uses this type of approach. See http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html#companion-objects-of-a-type
Scala 标准库使用这种方法。请参阅http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html#companion-objects-of-a-type
回答by Atais
Short and simple
简短而简单
Try(option.get)
no need for fancy mapping. In case the option is empty you get an error like:
不需要花哨的映射。如果该选项为空,您会收到如下错误:
java.util.NoSuchElementException: None.get
回答by Régis Jean-Gilles
If you want to use an Either, you can use Option.toRight:
如果要使用Either,可以使用Option.toRight:
def getValidBRefForReferencedA(aRef: ARef): Either[Throwable,BRef] = {
for {
a <- get[A](aRef).toRight[Throwable](new Exception("Invalid ARef")).right
bRef <- validBRefs.find(_ == a.bRef).toRight(new MismatchException("No B found matching A's B-ref")).right
} yield bRef
}
Using a Try, you can simply write your code in a very procedural way, by throwing appropriate exceptions where needed and wrapping the whole with
Try.apply(which will catch the exception and present them as Failureinstances).
使用 a Try,您可以简单地以非常程序化的方式编写代码,方法是在需要的地方抛出适当的异常并用 包装整个
Try.apply(这将捕获异常并将它们呈现为Failure实例)。
def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = Try {
val a = get[A](aRef).getOrElse(throw new Exception("Invalid ARef"))
validBRefs.find(_ == a.bRef).getOrElse(throw new MismatchException("No B found matching A's B-ref"))
}
回答by pagoda_5b
[Edited to identify different failures]
[编辑以识别不同的故障]
Tried to simplify
试图简化
def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {
val abRef = for {
a <- get[A](aRef)
bRef = a.bRef
result = Either.cond(validBRefs.contains(bRef), bRef, "Invalid B Reference")
} yield result
abRef.map {
case Right(bRef) => Success(bRef)
case Left(error) => Failure(new InvalidReferenceException(error))
}.getOrElse(Failure(new MismatchException("No B found matching A's B-ref")))
}
回答by Shadowlands
I have worked out an alternative solution, although it still doesn't allow me to specify a different failure message for the case that the Option[A] is None versus the BRef not being valid:
我已经制定了一个替代解决方案,尽管它仍然不允许我为 Option[A] 为 None 而 BRef 无效的情况指定不同的失败消息:
def getValidBRefForReferencedA(aRef: ARef): Try[BRef] =
Try {
(for {
a <- get[A](aRef)
bRef = a.bRef
_ <- bs.find(_ == bRef)
} yield (bRef)) getOrElse (throw new MismatchException("No B found matching A's B-ref"))
}
I guess I am expecting it should be possible to have a way to quickly convert the returned Option[A] into a Try (in a suitably idiomatic Scala way - eg. inside a for-comprehension), then continue the processing (obtaining and checking the b-ref) while setting any appropriate Failures along the way.
我想我期望应该有一种方法可以将返回的 Option[A] 快速转换为 Try(以适当的 Scala 惯用方式 - 例如在 for-comprehension 中),然后继续处理(获取和检查b-ref) 同时设置任何适当的失败。

