理解在scala中传递参数的困惑

时间:2014-07-18 14:22:02

标签: scala apache-spark

Spark的RDD中的两个groupBy方法声明为:

def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
def groupBy[K](f: T => K, numPartitions: Int)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]

我将函数f定义为:

def f(x: Int): Int = x % 2

我可以将f作为groupBy传递给第一个rdd.groupBy(f)。为什么我不能将f作为groupBy传递到第二个rdd.groupBy(f, 10)?我必须使用rdd.groupBy(f(_), 10)rdd.groupBy(x => f(x), 10)

1 个答案:

答案 0 :(得分:3)

  

我将函数f定义为:

def f(x: Int): Int = x % 2

这不是一个函数,那是一个方法。这两个从根本上不同:

  • 方法可以是通用的,功能不可以。
  • 方法可以使用带有默认参数的可选参数,但函数不能。
  • 方法可以有varargs,函数不能。
  • 方法可以有隐式参数,函数不能。

这些是函数与方法相比的4个限制。现在,如果它们如此受限制,我们为什么要使用它们呢?嗯,功能有一个主要优点:

  • 函数是对象,方法不是(它们属于对象。)

这意味着:函数可以分配给val s / var,它们可以作为参数传递给函数,方法和构造函数,它们可以从函数和方法返回。方法无法做到这一点:Scala是一种面向对象的语言,程序可以操作的所有实体都是对象......而方法则不是。

那么,为什么

rdd.groupBy(f)

工作?

好吧,您可以通过η-expansion将方法转换为部分应用的函数(此处“部分应用”表示“部分应用于this”,而不是参数的子集)

val fn = f _
// => fn: Int => Int = <function1>

这里,与Scala中的情况一样,下划线用作占位符(在这种情况下,用于尚未提供的参数)。我们修复了方法的this并将参数保持打开状态,并创建了与该方法对应的函数。

一些的情况下,Scala会知道你想要执行η-expansion甚至而不用明确提供下划线。这就是为什么

rdd.groupBy(f)

的工作原理。这称为隐式η-扩展(Scala语言规范的第6.26.2节案例3),由于含糊不清,仅适用于有限数量的情况。

然而,在解释了所有这些之后,我必须承认,我不明白为什么你的第二个例子不起作用。根据我对规范的解读,它应该。

IOW:您似乎遇到的基本问题是您混淆了函数和方法,但在这个特殊情况中,它应该实际工作(至少根据我对规范的解释,虽然显然不是根据编译器编写者的解释而来的。)