我想实现以下功能:
case class ValidatorClean[+A](apply: A => A)
implicit val traversableValidatorClean = ValidatorClean[Traversable[String]](_.map(_.trim))
使得例如每当需要ValidatorClean[Seq[String]]
或ValidatorClean[List[String]]
时就拾取traversableValidatorClean
。
然而,这并没有编译,错误为
covariant type A occurs in contravariant position in type => A => A of value apply
我知道函数的输入是反变的,输出是协变的,但我希望A
在apply
中表现不变。也就是说,apply
中的函数将始终返回与其输入完全相同的类型。
这能实现吗?
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
没有map
方法,因此它无法工作。