Las*_*asf 5 scala covariance generic-variance
这不会编译:
class MyClass[+A] {
def myMethod(a: A): A = a
}
//error: covariant type A occurs in contravariant position in type A of value a
Run Code Online (Sandbox Code Playgroud)
好吧,很公平。但这确实可以编译:
class MyClass[+A]
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myMethod(a: A): A = a
}
Run Code Online (Sandbox Code Playgroud)
这使我们能够规避方差检查给我们带来的任何问题:
class MyClass[+A] {
def myMethod[B >: A](b: B): B = b //B >: A => B
}
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myExtensionMethod(a: A): A = mc.myMethod(a) //A => A!!
}
val foo = new MyClass[String]
//foo: MyClass[String] = MyClass@4c273e6c
foo.myExtensionMethod("Welp.")
//res0: String = Welp.
foo.myExtensionMethod(new Object())
//error: type mismatch
Run Code Online (Sandbox Code Playgroud)
感觉就像在作弊。应该避免吗?还是有一些合理的原因使编译器让它滑动?
更新:
请考虑以下示例:
class CovariantSet[+A] {
private def contains_[B >: A](b: B): Boolean = ???
}
object CovariantSet {
implicit class ImpCovSet[A](cs: CovariantSet[A]) {
def contains(a: A): Boolean = cs.contains_(a)
}
}
Run Code Online (Sandbox Code Playgroud)
看来我们似乎已经设法实现了不可能的目标:仍然满足的协变“集合” A => Boolean。但是,如果这不可能,那么编译器是否应该禁止它?
我不认为它比脱糖后的版本更作弊:
val foo: MyClass[String] = ...
new MyImplicitClass(foo).myExtensionMethod("Welp.") // compiles
new MyImplicitClass(foo).myExtensionMethod(new Object()) // doesn't
Run Code Online (Sandbox Code Playgroud)
原因是MyImplicitClass构造函数上的类型参数在myExtensionMethod考虑之前就被推断出来了。
最初我想说它不会让你“规避方差检查给我们带来的任何问题”,因为扩展方法需要用方差合法方法来表达,但这是错误的:它可以在伴生对象并使用私有状态。
我看到的唯一问题是,修改代码的人可能会感到困惑(甚至不阅读它,因为那些人看不到非编译代码)。我不认为这是一个大问题,但如果没有在实践中尝试,很难确定。
| 归档时间: |
|
| 查看次数: |
216 次 |
| 最近记录: |