使用traits增强java类,如何在java字段内部声明trait?

ide*_*ird 10 scala traits

我的目标是使用特征混合来增强现有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

fot*_*ton 8

是的,这是可行的,但不是试图访问你想(这是最容易坏的想法)混合在类的私有字段,你想声明自我型RectangleLikejava.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)