Scala:使协变类型不变

时间:2016-05-12 02:51:58

标签: scala covariance contravariance

我想实现以下功能:

case class ValidatorClean[+A](apply: A => A)

implicit val traversableValidatorClean = ValidatorClean[Traversable[String]](_.map(_.trim))

,以便在需要traversableValidatorCleanValidatorClean[Seq[String]]时选择ValidatorClean[List[String]]

但是,这不会编译,错误

covariant type A occurs in contravariant position in type => A => A of value apply

我知道函数的输入和输出中的协变是逆变的,但我希望Aapply中不变地表现。也就是说,apply中的函数将始终返回与其输入完全相同的类型。

这可以实现吗?

1 个答案:

答案 0 :(得分:1)

ValidatorClean协变是没有意义的。

让我们说:

abstract class Animal

object Animal {
    def validate[A <: Animal : ValidatorClean](animal: A): Animal =
        implicitly[ValidatorClean[A]].apply(animal)
}

class Cat {
    def canMeow: Boolean = ???
}

class Dog {
    def canBark: Boolean = ???
}

通过提出ValidatorClean协变,您说ValidatorClean[Dog]ValidatorClean[Animal]的子类型,这意味着如果您需要ValidatorClean[Animal],您还会ValidatorClean[Dog]就此事而言。

所以我们假设我们有ValidatorClean[Cat],但我们不知道它是子类型。

Animal

现在我写道:

 val unknown: Animal = new Dog // perhaps the Animal really came from a List

会发生什么?如果有可用的隐式Animal.validate(unknown) ValidatorClean[Dog]会很乐意接受它。也许它看起来像:

validate

但是,接受implicit validateDog = ValidatorClean[Dog](dog => if (dog.canBark) dog else ???) 并调用Dog的此功能如何处理任意canBark?它不能。

同样,即使Animal没有ValidatorClean[Traversable[String]]方法,ValidatorClean[Any]也会为Any解析,因此无法使用。

相关问题