使用 Either 处理 Scala 代码中的故障
Option
monad 是在 Scala 中处理有或无事物的一种很好的表达方式。 但是,如果在“什么也没发生”时需要记录一条消息怎么办? 根据 Scala API 文档,
Either 类型通常用作 scala.Option where Left 的替代方案 代表失败(按照惯例)并且 Right 类似于 Some。
然而,我没有运气找到使用 Either 的最佳实践或涉及 Either 处理失败的良好现实示例。 最后,我为自己的项目编写了以下代码:(
def logs: Array[String] = {
def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
val config = ca.getConfiguration(PID, null)
config.properties getOrElse immutable.Map.empty
}
def checkType(any: Any): Option[Array[String]] = any match {
case a: Array[String] => Some(a)
case _ => None
}
def lookup: Either[(Symbol, String), Array[String]] =
for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
yield array
lookup.fold(failure => { failure match {
case ('warning, msg) => log(LogService.WARNING, msg)
case ('debug, msg) => log(LogService.DEBUG, msg)
case _ =>
}; new Array[String](0) }, success => success)
}
请注意,这是来自真实项目的片段,因此它不会自行编译)
我很高兴知道您如何使用 在您的代码中和/或重构上述代码的更好想法。
Option
monad is a great expressive way to deal with something-or-nothing things in Scala. But what if one needs to log a message when "nothing" occurs? According to the Scala API documentation,
The Either type is often used as an
alternative to scala.Option where Left
represents failure (by convention) and
Right is akin to Some.
However, I had no luck to find best practices using Either or good real-world examples involving Either for processing failures. Finally I've come up with the following code for my own project:
def logs: Array[String] = {
def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
val config = ca.getConfiguration(PID, null)
config.properties getOrElse immutable.Map.empty
}
def checkType(any: Any): Option[Array[String]] = any match {
case a: Array[String] => Some(a)
case _ => None
}
def lookup: Either[(Symbol, String), Array[String]] =
for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
yield array
lookup.fold(failure => { failure match {
case ('warning, msg) => log(LogService.WARNING, msg)
case ('debug, msg) => log(LogService.DEBUG, msg)
case _ =>
}; new Array[String](0) }, success => success)
}
(Please note this is a snippet from a real project, so it will not compile on its own)
I'd be grateful to know how you are using Either
in your code and/or better ideas on refactoring the above code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Either 用于返回可能的两个有意义的结果之一,与用于返回单个有意义的结果或不返回任何结果的 Option 不同。
下面给出一个容易理解的例子(前段时间在 Scala 邮件列表上流传):
顾名思义,如果“block”执行成功,就会返回“Right()”。 否则,如果抛出 Throwable,它将返回“Left()”。 使用模式匹配来处理结果:
希望有帮助。
Either is used to return one of possible two meaningful results, unlike Option which is used to return a single meaningful result or nothing.
An easy to understand example is given below (circulated on the Scala mailing list a while back):
As the function name implies, if the execution of "block" is successful, it will return "Right(<result>)". Otherwise, if a Throwable is thrown, it will return "Left(<throwable>)". Use pattern matching to process the result:
Hope that helps.
Scalaz 库有类似的东西,名为 Validation。 它比“Either”更惯用,用作“获得有效结果或失败”。
验证还允许累积错误。
编辑:“alike” Either 是完全错误的,因为 Validation 是一个应用函子,而 scalaz Either,名为 \/ (发音为“disjonction”或“either”),是一个 monad。
验证可能会累积错误的事实就是因为这种性质。 另一方面, / 具有“提前停止”的性质,在它遇到的第一个 -\/ (读为“左”,或“错误”)处停止。 这里有一个完美的解释: http://typelevel.org/blog /2014/02/21/error-handling.html
请参阅:http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
根据评论的要求,复制/粘贴上述链接(删除了一些行):
Scalaz library has something alike Either named Validation. It is more idiomatic than Either for use as "get either a valid result or a failure".
Validation also allows to accumulate errors.
Edit: "alike" Either is complettly false, because Validation is an applicative functor, and scalaz Either, named \/ (pronounced "disjonction" or "either"), is a monad.
The fact that Validation can accumalate errors is because of that nature. On the other hand, / has a "stop early" nature, stopping at the first -\/ (read it "left", or "error") it encounters. There is a perfect explanation here: http://typelevel.org/blog/2014/02/21/error-handling.html
See: http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
As requested by the comment, copy/paste of the above link (some lines removed):
您发布的片段看起来非常做作。 您可以在以下情况下使用 Either:
将异常转变为左确实是一个常见的用例。 与 try/catch 相比,它的优点是可以将代码保持在一起,如果异常是预期结果,这是有意义的。 处理 Either 的最常见方法是模式匹配:
处理
Either
的另一种有趣方法是当它出现在集合中时。 当对集合进行映射时,抛出异常可能不可行,并且您可能希望返回除“不可能”之外的一些信息。 使用 Either 可以让您在不增加算法负担的情况下做到这一点:在这里,我们获得图书馆中所有作者的列表,以及没有作者的书籍列表。 所以我们可以进一步相应地处理它:
所以,基本的 Either 用法就是这样的。 这不是一个特别有用的类,但如果是的话,您以前应该已经见过它了。 另一方面,它也并非毫无用处。
The snippet you posted seems very contrived. You use Either in a situation where:
Turning an exception into a Left is, indeed, a common use case. Over try/catch, it has the advantage of keeping the code together, which makes sense if the exception is an expected result. The most common way of handling Either is pattern matching:
Another interesting way of handling
Either
is when it appears in a collection. When doing a map over a collection, throwing an exception might not be viable, and you may want to return some information other than "not possible". Using an Either enables you to do that without overburdening the algorithm:Here we get a list of all authors in the library, plus a list of books without an author. So we can then further process it accordingly:
So, basic Either usage goes like that. It's not a particularly useful class, but if it were you'd have seen it before. On the other hand, it's not useless either.
Cats 有一个很好的方法来从抛出异常的代码中创建 Either:
in https://typelevel.org/cats/datatypes/either.html#working-with-exception-y-code
Cats has a nice way to create an Either from exception-throwing code:
in https://typelevel.org/cats/datatypes/either.html#working-with-exception-y-code