Scala - 构造函数中无法识别方法

发布于 2024-11-26 15:13:42 字数 1043 浏览 0 评论 0原文

我正在尝试扩展 javax.swing.Timer,但它只有一个构造函数,即

Timer(int delay, ActionListener listener) 

我不希望 Scala 中的子类在其构造函数中采用 Java ActionListener 。我在非常旧的线程中读到“没有办法直接调用超类构造函数;你必须传递你自己的类的主构造函数”,所以看起来我被困住了主构造函数中的 ActionListener。因此,我添加了一个辅助构造函数:

case class TimerEvent (source: AnyRef) extends swing.event.Event

class ScalaTimer2 (delay: Int, listener: java.awt.event.ActionListener)
      extends javax.swing.Timer(delay, listener) with swing.Publisher {
  outer =>
  def this(delay: Int) = {
    this(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) {
        publish(TimerEvent(outer))   // <-- publish not recogonized
      }
    })
//    publish(TimerEvent(outer)) // <-- publish recognized here
  }
}

但是我收到编译错误 error: not find: valuepublish ...为什么?以及如何修复?

I'm trying to extend javax.swing.Timer, but it only has one constructor, which is

Timer(int delay, ActionListener listener) 

I do not want my subclass in Scala to take a Java ActionListener in its constructor. I read in a very old thread that "there is no way to call a superclass constructor directly; you have to pass by the primary constructor of your own class", so it looks like I'm stuck with the ActionListener in the primary constructor. So I've added an auxiliary constructor thus:

case class TimerEvent (source: AnyRef) extends swing.event.Event

class ScalaTimer2 (delay: Int, listener: java.awt.event.ActionListener)
      extends javax.swing.Timer(delay, listener) with swing.Publisher {
  outer =>
  def this(delay: Int) = {
    this(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) {
        publish(TimerEvent(outer))   // <-- publish not recogonized
      }
    })
//    publish(TimerEvent(outer)) // <-- publish recognized here
  }
}

However I get a compile error error: not found: value publish ... why? And how to fix?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

断念 2024-12-03 15:13:42

这里实际上有两个问题:在构造函数完成之前,publishouter 都将不可用。 Scala 似乎有一个规则,即在主构造函数完成之前,不能在辅助构造函数中引用 this 实例。例如,以下内容将无法编译:

class Foo (x: Unit) { def this() { this(println(this)) } }

不使用辅助构造函数,而是在伴生对象上定义工厂方法怎么样?

object ScalaTimer2 {
  def apply(delay: Int): ScalaTimer2 = {
    lazy val ret: ScalaTimer2 = new ScalaTimer2(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) {
        ret.publish(TimerEvent(ret))
      }
    })
    ret
  }
}

请注意,ret 的前向引用需要使用lazy val 而不仅仅是val。大概是在构造函数返回之前才调用 actionPerformed ,否则 ret 将因无限递归而无效。

There are actually two problems here: both publish and outer will not be available until the constructor has completed. Scala seems to have a rule that this instance cannot be referenced in an auxiliary constructor until the primary constructor has completed. For example, the following will fail to compile:

class Foo (x: Unit) { def this() { this(println(this)) } }

Rather than an auxiliary constructor, how about defining a factory method on the companion object?

object ScalaTimer2 {
  def apply(delay: Int): ScalaTimer2 = {
    lazy val ret: ScalaTimer2 = new ScalaTimer2(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) {
        ret.publish(TimerEvent(ret))
      }
    })
    ret
  }
}

Note that the forward reference of ret requires the use of a lazy val instead of just val. Presumably actionPerformed is not called until the constructor returns, otherwise ret will be invalid due to infinite recursion.

诗化ㄋ丶相逢 2024-12-03 15:13:42

这是我在这种特殊情况下发现的一种解决方法:发送一个虚拟的 ActionListener,然后删除并替换为真实的 ActionListener。

class ScalaTimer2 private (delay: Int, listener: java.awt.event.ActionListener)
      extends javax.swing.Timer(delay, listener) with swing.Publisher {
  outer =>

  def this(delay: Int) = 
    this(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) { } // dummy
    })
  removeActionListener(listener)

  addActionListener(new java.awt.event.ActionListener {
    def actionPerformed(e: java.awt.event.ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })
}

编辑:另一个技巧:将主构造函数设置为私有,这样就不会错误地尝试使用您自己的 ActionListener 进行构造。

编辑 2:或者通过在签名中传递匿名 ActionListener 来完全避免辅助构造函数。

编辑 3 - 已解决! :我刚刚在Javadoc中读到传递给构造函数的ActionListener可以为null!所以我们真正需要的是:

class ScalaTimer2 (delay: Int) extends Timer(delay, null) with Publisher {
  outer =>
  addActionListener(new ActionListener {
    def actionPerformed(e: ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })
}

Here's a workaround I found in this particular case: send a dummy ActionListener then remove and replace with the real one.

class ScalaTimer2 private (delay: Int, listener: java.awt.event.ActionListener)
      extends javax.swing.Timer(delay, listener) with swing.Publisher {
  outer =>

  def this(delay: Int) = 
    this(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) { } // dummy
    })
  removeActionListener(listener)

  addActionListener(new java.awt.event.ActionListener {
    def actionPerformed(e: java.awt.event.ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })
}

Edit: another trick: making the primary constructor private so that there's no opportunity to mistakenly try constructing with your own ActionListener.

Edit 2: or avoid the auxiliary constructor altogether by passing an anonymous ActionListener in the signature.

Edit 3 - solved! : I just read in the Javadoc that the ActionListener passed to the constructor can be null! So all we actually need is:

class ScalaTimer2 (delay: Int) extends Timer(delay, null) with Publisher {
  outer =>
  addActionListener(new ActionListener {
    def actionPerformed(e: ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文