取自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又有一个body;不知怎么的,它是在withCallback返回的数据帧上调用的,但我不理解语法。
count()
方法实际上没有自己的主体。看起来像count()
的主体实际上是一个函数文字,它定义了withCallback
的"action"参数。严格地说,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")}.""")
现在,通过你自己的小"语言扩展"(这真的只是一种调用函数的有趣方式),你有了一个很好的小程序,它让你十有八九都很开心。