这个scala代码中发生了什么?回调函数

时间:2016-05-02 19:38:13

标签: scala apache-spark

取自Apache Spark,Dataset.scala(https://github.com/apache/spark/blob/0c47e274ab8c286498fa002e2c92febcb53905c6/sql/core/src/main/scala/org/apache/spark/sql/Dataset.scala

第2132行:

/**
  * Returns the number of rows in the [[Dataset]].
  * @group action
  * @since 1.6.0
  */
def count(): Long = withCallback("count", groupBy().count()) { df =>
  df.collect(needCallback = false).head.getLong(0)
}

第2393行:

/**
  * Wrap a Dataset action to track the QueryExecution and time cost, then report to the
  * user-registered callback functions.
  */
private def withCallback[U](name: String, df: DataFrame)(action: DataFrame => U) = {
  try {
      df.queryExecution.executedPlan.foreach { plan => plan.resetMetrics()
    }
    val start = System.nanoTime()
    val result = action(df)
    val end = System.nanoTime()
    sqlContext.listenerManager.onSuccess(name, df.queryExecution, end - start)
    result
  } catch {
  case e: Exception =>
    sqlContext.listenerManager.onFailure(name, df.queryExecution, e)
    throw e
  }
}

这里发生了什么?我不明白count()是如何在某种程度上等于withCallback并且有一个正文;不知何故,它被withCallback返回的数据帧调用,但我不理解语法。

1 个答案:

答案 0 :(得分:3)

count()方法实际上并没有自己的身体。看起来像count()的主体实际上是一个函数文字,它定义了'动作' withCallback的论点。严格来说,count()本身只是对方法withCallback(name, df)(action)的调用。 (方法可以在Scala中有多个参数列表。)withCallback的值是result,这是action函数计算的任何值。

然而,"混乱"你正在经历的是故意的。这个成语 - 一个具有终端参数列表的方法,其类型是函数或按名称值 - 允许用户定义语法扩展的语法。我们习惯于使用具有特殊语法的语言,如...

try {
  // your code here
}

在Scala中,您可以编写自己的函数,如...

// don't ask me why you would want to do this
def unreliably[T]( operation : =>T ) : Option[T] = {
   if (scala.math.random < 0.1) Some(operation) else None
}

...用户可以像

一样打电话
unreliably {
  // your code here
}

它看起来就像新的语言语法!为了使它更像你的激励示例,我们可以将定义修改为必须参数列表......

// don't ask me why you would want to do this
def unreliably[T]( probability : Double )( operation : =>T ) : Option[T] = {
   if (scala.math.random < probability) Some(operation) else None
}

现在,我们可以将函数称为...

unreliably( probability = 0.9 ) {
  // your code here
}

...并且您的代码有90%的可能性被执行。代码定义了一个表达式,而不仅仅是一些无值语句,所以你也可以编写

val result = unreliably( probability = 0.9 ) {
   "great day"
}

result的类型为Option[String],因此您可以使用...

println(s"""It's a ${result.getOrElse("terrible day")}.""")

现在,通过你自己的小语言扩展&#34; (这真的只是一个有趣的方式来调用一个函数),你有一个很好的小程序,可以让你在十天中九天快乐。