【问题标题】:Scala - method not recognized in constructorScala - 构造函数中无法识别的方法
【发布时间】:2011-07-26 22:32:47
【问题描述】:

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

Timer(int delay, ActionListener listener) 

我不希望 Scala 中的子类在其构造函数中使用 Java ActionListener。我在very old thread 中读到“没有办法直接调用超类构造函数;你必须通过你自己类的主构造函数”,所以看起来我在主类中坚持使用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 found: value publish ...为什么?以及如何解决?

【问题讨论】:

标签: scala constructor


【解决方案1】:

这里实际上有两个问题: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会因为无限递归而失效。

【讨论】:

    【解决方案2】:

    这是我在这种特殊情况下找到的一种解决方法:发送一个虚拟的 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))
        }
      })
    }
    

    编辑:另一个技巧:创建主构造函数private,这样就没有机会错误地尝试使用您自己的ActionListener 构造。

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-03-16
      • 1970-01-01
      • 1970-01-01
      • 2019-12-29
      • 1970-01-01
      • 2016-02-02
      • 1970-01-01
      • 2021-07-23
      • 2018-06-16
      相关资源
      最近更新 更多