我想实现以下功能:
case class ValidatorClean[+A](apply: A => A)
implicit val traversableValidatorClean = ValidatorClean[Traversable[String]](_.map(_.trim))
,以便在需要traversableValidatorClean
或ValidatorClean[Seq[String]]
时选择ValidatorClean[List[String]]
。
但是,这不会编译,错误
covariant type A occurs in contravariant position in type => A => A of value apply
我知道函数的输入和输出中的协变是逆变的,但我希望A
在apply
中不变地表现。也就是说,apply
中的函数将始终返回与其输入完全相同的类型。
这可以实现吗?
答案 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]
,您还会1}}或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
解析,因此无法使用。