Scala中新类中的"self"是什么意思?

4

最近我在阅读Spark的源代码。当我到达"org.apache.spark.deploy.SparkSubmit"类时,我对关键字"self"和运算符"=> "感到困惑。是否有人可以为我解释一下?

override def main(args: Array[String]): Unit = {
val submit = new SparkSubmit() {
  self =>

  override protected def parseArguments(args: Array[String]): SparkSubmitArguments = {
    new SparkSubmitArguments(args) {
      override protected def logInfo(msg: => String): Unit = self.logInfo(msg)

      override protected def logWarning(msg: => String): Unit = self.logWarning(msg)
    }
  }

  override protected def logInfo(msg: => String): Unit = printMessage(msg)

  override protected def logWarning(msg: => String): Unit = printMessage(s"Warning: $msg")

  override def doSubmit(args: Array[String]): Unit = {
    try {
      super.doSubmit(args)
    } catch {
      case e: SparkUserAppException =>
        exitFn(e.exitCode)
      case e: SparkException =>
        printErrorAndExit(e.getMessage())
    }
  }

}

顺便说一句:这个问题跟“重复”那个问题完全不同。虽然这两个问题很相似,但我问的是关于“new class”关键字附近的“self =>”,而不是scala类定义中带有“some name =>”的“重复”问题。 这是不同的问题。


这个标记为重复是错误的。另一个问题是关于声明自身类型,而这个问题中没有自身类型。 - Tim
这是对问题的答案:使用 self => 允许在 this 不可用的情况下使用此类的标识。具体来说,在 new SparkSubmitArguments 构造函数内,this 指针指的是新类而不是外部类。通过将 self 声明为外部类的别名,它可以在内部类中使用。 - Tim
@Tim,你知道如何申请“不正确的重复”投诉吗? - Cam Heo JianQiao
@CamHeoJianQiao,我已经调查过了,没有特定的机制来挑战这个问题,但我已经将此问题标记为“需要版主关注”,并解释了我的理由。由于您是作者,您可以编辑问题以指出这不是另一个问题的重复。 - Tim
@Tim 好的,我会尽快完成。 - Cam Heo JianQiao
显示剩余6条评论
2个回答

11

这个声明

self =>

被称为“自类型标注”,它创建了一个名为self的值,该值引用正在构建的类的实例。这可以在类的this值不可用的地方使用。特别是在嵌套类中,它可以用于内部,其中this指的是嵌套类,并且外部类的引用不会自动提供。

在您的情况下,self在此处使用:

new SparkSubmitArguments(args) {
  override protected def logInfo(msg: => String): Unit = self.logInfo(msg)

  override protected def logWarning(msg: => String): Unit = self.logWarning(msg)
}

这使得SparkSubmitArguments的新实例使用外部包含类的logInfologWarning方法。在这段代码的这个点上,您不能使用this,因为它会引用内部类,而不是外部类。(如果您在此处使用this,将会导致无限循环)。


5

这是this的别名。这样做是为了消除内部类中的自我引用歧义。

在内部类的作用域中使用this时,它指的是内部类的实例。如果你需要引用外部类,你需要一个别名:

  class Foo { self => 
    val x = 1
    new AnyRef { 
      val x = 2
      println(this.x) // 2
      println(self.x) // 1
    }
  }

如果删除 "self =>",会得到什么结果? - Cam Heo JianQiao
像这样的代码self.logInfo(msg)将无法编译,因为self未定义。 - Dima
你可以很容易地自己找到这类问题的答案,比如“如果……会发生什么”。顺便说一句,;)。 - Dima
自类型注释并不是无用的。如果没有它,您将无法从内部类调用logInfologWarning的外部实现。如果按照您的建议将self替换为this,则内部类中的logInfologWarning将会调用自身。 - Tim
@Tim,哦,你说得对!我没有注意到那里有两个内部类。 - Dima
简单、清晰、简洁。如果所有的Stackoverflow答案都能像这样就好了。 - Ted

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接