1

我很难找到这个错误,似乎类Icon的字段pos隐藏了类Elementpos字段,仅在绘图函数中。

case class Vector2(val x: Float, val y: Float) { ... }

abstract class Element(var pos: Vector2) {
    def draw(): Unit
}

class Icon(pos: Vector2, var texture: String) extends Element(pos) {
  override def draw() {
    ...
    GL11.glTranslatef(pos.x, pos.y, 0f)
    ...
  }
}

稍后的:

// Create an icon with an initial position
val icon = new Icon(pos = Vector2(40,20), "crosshair")

// Draw all elements
elements.foreach{_.draw()} // => draws icon at (40,20)

// Setting a new position for icon
icon.pos = Vector2(100,200)

// See if it worked
Log.info(icon.pos.toString()) // => this prints Vector2(100,200)

// Draw all elements
elements.foreach{_.draw()} // => still draws icon at (40,20)

我看过这篇文章并尝试过:

  • 在基类中使 var 抽象:这可以防止我为 Element 设置新的 pos
  • 重命名构造函数参数(例如_pos):我不会这样做,因为这会搞砸API
  • 覆盖派生类中的 var:只是编译器告诉我不能覆盖可变变量

出路是什么?

4

2 回答 2

2

只需明确取消引用this

class Icon(pos: Vector2, var texture: String) extends Element(pos) {
  override def draw() {
    ...
    GL11.glTranslatef(this.pos.x, this.pos.y, 0f)
    ...
  }
}

鉴于阴影只发生在 内部Icon,其他任何地方(包括在派生类中)您可以继续使用pos(不需要this.pos)。

更新:不用等待,这不起作用!我称之为编译器错误。似乎即使它们不应该(恕我直言)是同一件事,this.pos也被视为一样。pos不过有一个简单的解决方法:

class Icon(pos: Vector2) extends Element(pos) {
  private def self = this
  override def draw() {
    println(self.pos.x, self.pos.y, 0f)
  }
}

更新 2:这是对评论的回复,不适合其他评论。

兰德尔舒尔茨 说:

我不相信这是一个错误。

好吧,它看起来确实像是一个错误,或者至少是我想要说明理由的不一致之处。

首先要注意的是,在我上面的工作中,self eq this. 它们确实指向相同的引用,此外还具有相同的静态类型。那么为什么会返回两个不同的self.pos东西this.pos(不管返回的“正确”东西是什么)?换句话说,self是 的别名this,并且别名的行为必须都相同。

现在,我认为this.pos应该表示变量 inElement而不是Icon构造函数的参数的原因很简单。这个参数前面没有,val因此实际上只是一个参数(不是 a val)。因此,Icon仅由于词法作用域,它才可以在课堂上访问。它不是的成员Icon,甚至不是私有的(在引擎盖下生成私有字段的事实不会改变语言的语义)。如果pos参数不是成员,则没有理由this.pos应该退回它。显然,这个论点归结为参数是否也是类的成员。对我来说显然不是,但如果实际上它应该自动成为成员(我仍在查看规范中是否提到这一点),那么self.pos返回参数的值而不是当前的值确实是合乎逻辑的基类中 var 的值(但这仍然不能解释如何self.pos以及this.pos可能意味着不同的事情)。

这就是存在自我类型(使用除此之外的名称的(通常)不受约束的种类)存在的原因之一。

嗯,不。自我类型无关紧要。不受约束的自类型只是引入了一个别名,因此别名指向相同的引用this(如果不受约束,则具有相同的静态类型)。所以使用别名应该不会改变返回的内容。实际上,它没有:

class Icon(pos: Vector2) extends Element(pos) { self =>
  override def draw() {
    println(self.pos.x, self.pos.y, 0f)
  }
}
val icon = new Icon(Vector2(1, 2))
icon.draw() // prints "(1.0,2.0,0.0)" as expected
icon.pos = Vector2(3, 4)
icon.draw() // oops, still prints "(1.0,2.0,0.0)"!

如您所见, self 类型没有帮助:self.pos仍然指向参数而不是变量。要解决此问题,您可能会尝试显式键入selfElement

class Icon(pos: Vector2) extends Element(pos) { self: Element =>

但这并没有改变任何东西。

于 2013-03-05T23:11:32.977 回答
0

构造函数参数在类体中是可见的,这就是事情的工作方式。有一个私人 val 影子一个公共 var 是很奇怪的,我同意你,但就是这样。在您展示的特定代码段中,您可以执行以下操作:

abstract class Element {
  def pos: Vector2
  def pos_=(x: Vector2): Unit
  def draw(): Unit
}

进而

class Icon(var pos: Vector2, var texture: String) extends Element {
  override def draw() {
    ...
    GL11.glTranslatef(pos.x, pos.y, 0f)
    ...
  }
}

但是,如果您只想使用一个值进行初始化,而不是在扩展的任何内容上Element声明 a ,这将无济于事。我自己的建议是避免使用构造函数,使用类似的东西,并在正文中初始化。varElementvarinitialPosvar

于 2013-03-06T00:55:26.327 回答