scalaz:如何处理验证中的不同错误类型?
scalaz: how to handle different error types in a Validation?
如果我有多个操作 return 一个 Validation[E, _]
具有固定错误类型的东西,我可以在理解中使用它们。例如:
val things: Validation[E, (Int, Double)] = for {
i <- getValidationOfInt
d <- getValidationOfDouble
} yield (i, d)
如果错误类型不同怎么办?假设我从 HTTP 读取并希望将字符串响应转换为 Int
.
import scalaz._; import Scalaz._
object ValidationMixing {
class HttpError
def getFromHttp: Validation[HttpError, String] = ???
def parseInt(json: String): Validation[Throwable, Int] =
Validation.fromTryCatchNonFatal(Integer.parseInt(json))
val intParsedFromHttp: Validation[Any, Int] = for {
s <- getFromHttp
i <- parseInt(s)
} yield i
}
这会编译,但这只是因为验证的错误类型是 Any
,是 Throwable
和 HttpError
的超类型。这不是很有帮助。
我可以想出各种表示这种组合错误类型的方法,这些方法比 Any
更有用(例如 Validation[Error1 \/ Error2, Result]
用于存储,Validation[String, Result]
转换为错误消息,等),但它们都有缺点。
有没有惯用的方法来做到这一点?
既然没有人有更好的主意,我会留下我的答案以供将来参考。
如评论中所述,最好的方法是创建错误层次结构:
trait GenericError { /* some commond fields */}
case class MyNumericError(/* fields */)
然后在验证中使用 leftMap
以生成适当的错误:
Validation.fromTryCatchNonFatal(...).leftMap(t => MyNumericError(...))
这种方法有两个优点
- 首先,您将始终有一个
Validation[GenericError, T]
,因此在该验证的左侧部分没有不同的类型
- 第二个是,这有助于为开发人员和服务用户生成有意义的错误,还要注意,在您有很多上下文信息的情况下生成错误有助于此过程。
如果我有多个操作 return 一个 Validation[E, _]
具有固定错误类型的东西,我可以在理解中使用它们。例如:
val things: Validation[E, (Int, Double)] = for {
i <- getValidationOfInt
d <- getValidationOfDouble
} yield (i, d)
如果错误类型不同怎么办?假设我从 HTTP 读取并希望将字符串响应转换为 Int
.
import scalaz._; import Scalaz._
object ValidationMixing {
class HttpError
def getFromHttp: Validation[HttpError, String] = ???
def parseInt(json: String): Validation[Throwable, Int] =
Validation.fromTryCatchNonFatal(Integer.parseInt(json))
val intParsedFromHttp: Validation[Any, Int] = for {
s <- getFromHttp
i <- parseInt(s)
} yield i
}
这会编译,但这只是因为验证的错误类型是 Any
,是 Throwable
和 HttpError
的超类型。这不是很有帮助。
我可以想出各种表示这种组合错误类型的方法,这些方法比 Any
更有用(例如 Validation[Error1 \/ Error2, Result]
用于存储,Validation[String, Result]
转换为错误消息,等),但它们都有缺点。
有没有惯用的方法来做到这一点?
既然没有人有更好的主意,我会留下我的答案以供将来参考。
如评论中所述,最好的方法是创建错误层次结构:
trait GenericError { /* some commond fields */}
case class MyNumericError(/* fields */)
然后在验证中使用 leftMap
以生成适当的错误:
Validation.fromTryCatchNonFatal(...).leftMap(t => MyNumericError(...))
这种方法有两个优点
- 首先,您将始终有一个
Validation[GenericError, T]
,因此在该验证的左侧部分没有不同的类型 - 第二个是,这有助于为开发人员和服务用户生成有意义的错误,还要注意,在您有很多上下文信息的情况下生成错误有助于此过程。