我定义了以下异常层次结构:
/**
* Base class for all exceptions in this library
*/
trait MyAkkaHttpException {}
/**
* Thrown when there is a problem persisting data to a datastore
*/
case class PersistenceException(message: String)
extends Exception(message: String) with MyAkkaHttpException
/**
* Thrown when validation on an object fails
* @param errors
*/
case class ValidationException(message: String, errors: List[String])
extends Exception(message: String) with MyAkkaHttpException
以下代码:
class ContactFormService(contactFormPersistor: ContactFormPersistor) {
def handleForm(contactForm: ContactForm): ValidationNel[MyAkkaHttpException, String] = {
contactForm.validate() match {
case Success(_) => contactFormPersistor.persist(contactForm)
case Failure(e) =>
new ValidationException(message = "Error validating contact form",
errors = e.toList).failureNel[String]
}
}
}
contactFormPersistor.persist
返回ValidationNel[PersistenceException, String]
contactForm.validate()
返回ValidationNel[String, Boolean]
问题是handleForm
不接受PersistenceException
和ValidationException
是MyAkkaHttpException
的子类。我需要做些什么才能使它正确地意识到那些返回类型是有效的子类?
答案 0 :(得分:2)
尝试将ValidationNel[MyAkkaHttpException, String]
更改为Validation[NonEmptyList[MyAkkaHttpException], String]
。正如有人在评论中指出的那样,它只是在第一个类型参数中不是协变的类型别名。
type ValidationNel[E, +X] = Validation[NonEmptyList[E], X]
否则,NonEmptyList
和Validation
在所有参数中都是协变的。
这可能取决于您的scalaz
版本。就我可以浏览的最新版本而言,它看起来像ValidationNel
is no longer covariant in both arguments,但it previously was。这种变化可能是一个很好的理由:准备好不能使用ValidationNel
的Scalaz函数。
答案 1 :(得分:0)
问题是你需要对ValidationNel
的第一个类型参数进行协方差,而Validation
的这个特定捷径并没有考虑到这个协方差而设计*
根据我从评论交流中收集的信息,我相信这是正确的前进方向。声明自己的别名(或直接使用类型)
type MyValidationNel[+E, +X] = Validation[NonEmptyList[E], X]
*)但我觉得有一个原因在E
param没有协方差背后(因为scalaz通常知道有理由做事)
答案 2 :(得分:0)
Either
对左右两者都是协变的,所以我只是改用了它。