我的目标是使用特征混合来增强现有Java类的内部scala代码.例如,将java.awt.Rectangle.translate(dx,dy)等方法添加到java.awt.geom.Ellipse2D类中.为此,我创建了以下特征:
trait RectangleLike {
var x: Double // abstract vals to correspond to java class fields
var y: Double // I need these vars to refer to them inside translate method
def translate(dx: Double, dy: Double) {
x = x + dx
y = y + dy
}
// more concrete trait methods here
} // defines without errors in scala REPL
Run Code Online (Sandbox Code Playgroud)
然后在构造Ellipse时使用trait:
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
Run Code Online (Sandbox Code Playgroud)
但是当我在scala REPL中执行上面的脚本时,我得到以下输出:
<console>:8: error: overriding variable x in trait RectangleLike of type Double;
variable x in class Double of type Double has incompatible type;
other members with override errors are: y
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
Run Code Online (Sandbox Code Playgroud)
我怀疑这个错误是由于Scala实现变量的方式 - 作为私有字段和getter/setter方法对.我努力实现的目标是什么?是否有另一种方法来定义特征中的java类字段,然后在具体的特征方法中引用它们?
在此先感谢Jack Dimas
是的,这是可行的,但不是试图访问你想(这是最容易坏的想法)混合在类的私有字段,你想声明自我型RectangleLike是java.awt.geom.RectangularShape这样就可以像你Ellipse2D.Double一样使用你的特质Rectangle2D.Double.
下面是它的工作原理:
trait RectangleLike {
self: java.awt.geom.RectangularShape =>
def translate(dx: Double, dy: Double) {
setFrame(getX + dx, getY + dy, getX + getWidth, getY + getHeight)
}
}
object Test {
val foo = new java.awt.geom.Ellipse2D.Double with RectangleLike
}
Run Code Online (Sandbox Code Playgroud)
通过说self: java.awt.geom.RectangularShape =>你声明你的特质的自我类型,使你能够访问所有相应的方法,如必要的getter和setter,允许使用你的trait与所有后代RectangularShape,并"限制"你的特征,以便它只能使用作为一个混合类,它们本身就是它们的子类型RectangularShape.
上述场景的替代方案是使用所谓的您的视图,RectangularShape这也是一种常见的范例.为此,您可以申报一个班级
class RichRectangularShape(shape: java.awt.geom.RectangularShape) {
def translate(dx: Double, dy: Double) {
shape.setFrame(shape.getX + dx, shape.getY + dy,
shape.getX + shape.getWidth, shape.getY + shape.getHeight)
}
}
Run Code Online (Sandbox Code Playgroud)
Scala有一种隐式查看一种类型的对象作为另一种类型的对象的方法.如果碰巧在未在相应类型中声明的对象上调用方法,则编译器会尝试查找提供此方法的类型,特别是还要尝试查找隐式转换,以便可以将原始对象视为后一种类型的实例.为此,您通常会将伴随对象声明RichRectangularShape为:
object RichRectangularShape {
implicit def mkRRS(shape: java.awt.geom.RectangularShape): RichRectangularShape =
new RichRectangularShape(shape)
}
Run Code Online (Sandbox Code Playgroud)
然后:
scala> import RichRectangularShape._
import RichRectangularShape._
scala> val foo = new java.awt.geom.Ellipse2D.Double
foo: java.awt.geom.Ellipse2D.Double = java.awt.geom.Ellipse2D$Double@0
scala> foo.translate(5,2)
scala> foo.getX
res1: Double = 5.0
scala> foo.getY
res2: Double = 2.0
scala> :t foo
java.awt.geom.Ellipse2D.Double
Run Code Online (Sandbox Code Playgroud)