scala - 使用扩展方法规避差异检查
问题描述
这不编译:
class MyClass[+A] {
def myMethod(a: A): A = a
}
//error: covariant type A occurs in contravariant position in type A of value a
好吧,够公平的。但这确实编译:
class MyClass[+A]
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myMethod(a: A): A = a
}
这让我们可以规避方差检查给我们带来的任何问题:
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
这感觉像是在作弊。应该避免吗?或者编译器让它滑动有什么正当理由吗?
更新:
考虑一下这个例子:
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)
}
}
显然我们已经设法实现了不可能的目标:仍然满足A => Boolean
. 但如果这是不可能的,编译器不应该禁止它吗?
解决方案
我不认为它比脱糖后的版本更作弊:
val foo: MyClass[String] = ...
new MyImplicitClass(foo).myExtensionMethod("Welp.") // compiles
new MyImplicitClass(foo).myExtensionMethod(new Object()) // doesn't
原因是MyImplicitClass
构造函数的类型参数在考虑之前被推断出来myExtensionMethod
。
最初我想说它不会让你“规避方差检查给我们带来的任何问题”,因为扩展方法需要用方差合法方法来表达,但这是错误的:它可以在伴随对象并使用私有状态。
我看到的唯一问题是修改代码的人可能会感到困惑(甚至不阅读它,因为那些人不会看到非编译代码)。我不认为这会是一个大问题,但是如果没有在实践中尝试,很难确定。
推荐阅读
- azure - 当持久性卷声明超过存储时会发生什么?
- flutter - 如何使卡片像颤动的标签一样可滑动?
- extjs - 基于 extjs 网格中的另一个组合框填充字段
- swift - 快速获取日期范围内的日期名称和日期重复次数
- android - 将基于 Web 的数据库管理应用程序转换为移动应用程序以使其离线工作
- arduino - 如何从 Arduino“9 Axis Motion Shield”获取数据和校准
- laravel - 如何在 laravel 中使用相同的表单进行添加和编辑
- .net-core - 编译和使用自定义 Dotnet/CoreFx
- ruby-on-rails - Active Record:未在嵌套关系中分配 User_id
- jquery - 单击添加新行按钮第一行单选按钮值在 jquery 中未定义