Scala类型签名与子类失败

时间:2016-07-22 15:36:36

标签: scala scalaz

我定义了以下异常层次结构:

/**
  * 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不接受PersistenceExceptionValidationExceptionMyAkkaHttpException的子类。我需要做些什么才能使它正确地意识到那些返回类型是有效的子类?

3 个答案:

答案 0 :(得分:2)

尝试将ValidationNel[MyAkkaHttpException, String]更改为Validation[NonEmptyList[MyAkkaHttpException], String]。正如有人在评论中指出的那样,它只是在第一个类型参数中不是协变的类型别名。

type ValidationNel[E, +X] = Validation[NonEmptyList[E], X]

否则,NonEmptyListValidation在所有参数中都是协变的。

编辑:

这可能取决于您的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对左右两者都是协变的,所以我只是改用了它。