【发布时间】:2020-01-02 14:11:00
【问题描述】:
假设我有一个带有链接函数的类
class Vehicle {
protected var position: (Int, Int) = (0, 0)
def moveLeft(meters: Int): Vehicle = {
position = position._1 - meters -> position._2
this
}
def moveForward(meters: Int): Vehicle = {
position = position._1 -> (position._2 + meters)
this
}
}
所以每个方法都返回实例本身
现在我想继承 Vehicle 并向新类添加一些方法
class Helicopter extends Vehicle {
protected var verticalDimension: Int = 0
def flyIntoTheSky(meters: Int): Helicopter = {
verticalDimension += meters
this
}
}
如果我将创建一个新的类实例并从父级调用任何函数,例如
new Helicopter().moveLeft(10).moveForward(20)
我将无法调用新的类方法 flyIntoTheSky,因为方法返回类型是 Vehicle,而 Vehicle 对 Helicopter 的方法一无所知。
2 明显的解决方法: 要么使用 asInstanceOf
new Helicopter()
.moveLeft(10)
.moveForward(20).asInstanceOf[Helocopter]
.flyIntoTheSky(10000)
在新类中覆盖每个父方法
两种方式都不好看,我宁愿把所有这些类型的问题留给 Vehicle 类并忘记它,所以我找到了(如我所愿)解决方案,重写这样的方法
def moveLeft[T](meters: Int, vehicle: T = this): T = {
position = position._1 - meters -> position._2
this.asInstanceOf[T]
}
所以我希望返回类型将取自方法的第二个参数车辆,它始终等于默认值“this”,并将返回当前类型的值。不过很遗憾
new Helicopter().moveLeft(10)
仍然返回 Vehicle 类型的值 res0: Vehicle = Helicopter@1de81c37
所以第一个问题:为什么它不像我预期的那样工作。第二个:有什么漂亮的方法可以解决这个问题
谢谢
PS 在谷歌中,我在 Java 中找到了这个解决方案 https://www.andygibson.net/blog/article/implementing-chained-methods-in-subclasses/ ,但我不懂java,无法在scala中翻译它
【问题讨论】:
-
这被称为返回电流类型问题。有两种众所周知的解决方案,F-Bounded 多态性和typeclasses。检查this 以深入讨论解决此问题的两种技术。还有第三种选择使用 Type members,它类似于 F-Bounded 但更弱。最后,对于这种特定情况,由于您正在改变一个值而不是返回一个修改后的副本 (这应该是理想的) 我相信您可以使用
this.type作为返回类型。所以def moveLeft(...): this.type. -
谢谢,我会读...告诉某人“应该是理想的”的真正理由
标签: scala inheritance method-chaining