繁体   English   中英

在公共/开源Scala API中使用Try或Either进行错误处理是否存在问题?

[英]Are there problems using Try or Either for error handling in public/open source Scala APIs?

我注意到许多开源Scala API使用Future (如Slick)或Java风格的异常处理(如spray-json)而不是TryEither

在没有长时间运行或异步的简单开源API中返回TryEither是否存在问题? 我应该避免这些,如果是这样,我应该使用什么呢?

(显然,我更倾向于使用核心Scala API而不是第三方库,例如Scalaz,以避免迫使下游用户使用这些库。)

Try包装非异步操作的异常是很好的。
但是,我认为使用异常实例返回非异常错误条件是不正确的 当API是异步的并且使用Future时,我也是这样。 异常错误与业务错误混合容易导致API客户端(也就是我:)的错误处理不正确/不充分。

如果您仍然决定使用例外来表示您的业务错误,请记住异常带有隐藏价格:构建堆栈跟踪。 如果您创建自己的业务异常并混合使用scala.util.control.NoStackTrace则可以减轻这种scala.util.control.NoStackTrace

Scala标准库中的默认Either实现是无偏的,这意味着区分成功和失败的情况仅依赖于约定:

右是正确的(正确),因此左错(错误)。

不偏不倚的一面也让追随“快乐”的道路变得痛苦(或使错误恢复脱颖而出)

此时您的最佳选择(scala 2.11.6和相应的标准库)将根据您的依赖关系和要向用户公开的API而有所不同,但它不会来自scala标准库。

  • 如果您已经严重依赖scalaz,则Scalaz Validation\\/是一个选项
  • Scalactic的Or类型是一个很好的轻量级解决方案,如果你不想拉入整个scalaz。 它是成熟的,是从金字塔中提取出来的
  • (来自评论) Accord可能是一个选项,但我不太了解它与其他人比较。
  • (来自评论) Cat的Xor可能是一个选项,但我不太了解它与其他人比较。
  • Rapture modes允许您让API的客户端决定他想要取回的类型(例如,这种方法在parboiled2中使用)。 我不知道图书馆作者或编译时间的成本是多少。

您可能已经依赖于提供自己的validation类型的库。 例如,play-json有一个JsResult类型,其验证类似于能力。 根据您正在处理的内容重用类型可能是有意义的。

有一个进展和专家组呼叫至偏压任一类型添加到Scala的标准库。 上述两种解决方案具有已经能够累积错误的额外好处。

在以下情况下返回Try [T]:正确的结果和不正确的结果(即错误)之间存在语义差异。 这是因为:

  • 尝试是偏右的(它适用于地图,平面地图和for-comprehensions)。

  • 失败案例是一个Throwable,这很重要,因为throwable总是清楚地意味着甚至超出了代码边界的错误。

警告 :堆栈跟踪生成有时是一种开销,但并非总是如此! 在过早优化代码之前要三思而后行:堆栈跟踪带有许多有用的调试信息。 如果您以后发现您确实需要跳过堆栈跟踪生成,没问题:使用with NoStackTrace如上所示。

def validate(s:String):Try[String] = Option(s).filter(!_.isEmpty).map(Try(_)).getOrElse(new Exception("bad input") with NoStackTrace 

使用[L,R]时 :两种情况都可以接受,但它们是互斥的(即[Integer,Float])。 出于这个原因,尽管Scalaz的家伙们不得不对此发表评论,但我相信这两者都是公正的。

def parseNum(s:String):Either[Int,String] = Try(parseInt(s)).map(Left(_)).getOrElse(Right(s))

类似于Either 时使用Tuple ,但是当你有N时,非互斥值(你知道所有都有用)

def parseAndReturn(s:String):(Integer,String) = (parseInt(s), s) 

T可以为空时,或者当你处于与Try [T]相同的情况时, 返回一个选项[T] ,但是你没有给出关于为什么出错的原因。

def attemptToparse(s:String):Option[Result] = Try(parse(s)).toOption

我同意Try是捕获/通知异常,而不是返回业务/验证错误。 Scalaz是一个非常好的选择,但是如果你不想依赖它,我认为Either是好的,不偏不倚是令人讨厌但不是交易破坏者恕我直言:一旦你建立了Right是有效结果的约定,你可以“正确偏见”它与.rightProjection (如果你只想处理错误,你可以做左投影。另一种选择是使用Either的折叠fold[X](fa: (A) ⇒ X, fb: (B) ⇒ X): X myEither.fold(dealWithErrors _, happyPath _ ) fold[X](fa: (A) ⇒ X, fb: (B) ⇒ X): X喜欢myEither.fold(dealWithErrors _, happyPath _ ) (虽然这意味着dealWithErrorshappyPath返回相同的类型)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM