Scala 类型签名因子类而失败
Scala type signature failing with subclasses
我定义了以下异常层次结构:
/**
* 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
returns ValidationNel[PersistenceException, String]
contactForm.validate()
returns ValidationNel[String, Boolean]
问题是 handleForm
不接受 PersistenceException
和 ValidationException
是 MyAkkaHttpException
的子类。我需要做什么才能让它正确地意识到那些 return 类型是有效的子类?
尝试将 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, but it previously was。这种变化可能有一个很好的理由:准备好不能将 Scalaz 的函数用于 ValidationNel
.
问题是您需要 ValidationNel
的第一个类型参数的协变性,而 Validation
的这种特殊快捷方式在设计时并未考虑到这种协变性*
根据我从评论交流中收集到的信息,我相信这是正确的前进方向。声明自己的别名(或直接使用类型)
type MyValidationNel[+E, +X] = Validation[NonEmptyList[E], X]
*) 但是我确实有一种感觉,在 E
参数上没有协方差是有原因的(因为 scalaz 通常知道做事是有原因的)
Either
在左侧和右侧都是协变的,所以我只是切换到那个。
我定义了以下异常层次结构:
/**
* 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
returnsValidationNel[PersistenceException, String]
contactForm.validate()
returnsValidationNel[String, Boolean]
问题是 handleForm
不接受 PersistenceException
和 ValidationException
是 MyAkkaHttpException
的子类。我需要做什么才能让它正确地意识到那些 return 类型是有效的子类?
尝试将 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, but it previously was。这种变化可能有一个很好的理由:准备好不能将 Scalaz 的函数用于 ValidationNel
.
问题是您需要 ValidationNel
的第一个类型参数的协变性,而 Validation
的这种特殊快捷方式在设计时并未考虑到这种协变性*
根据我从评论交流中收集到的信息,我相信这是正确的前进方向。声明自己的别名(或直接使用类型)
type MyValidationNel[+E, +X] = Validation[NonEmptyList[E], X]
*) 但是我确实有一种感觉,在 E
参数上没有协方差是有原因的(因为 scalaz 通常知道做事是有原因的)
Either
在左侧和右侧都是协变的,所以我只是切换到那个。