1

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第一个groupByas rdd.groupBy(f)

为什么我不能直接传到f第二个groupByas rdd.groupBy(f, 10)?我必须使用rdd.groupBy(f(_), 10)or rdd.groupBy(x => f(x), 10)

4

1 回答 1

3

我将函数 f 定义为:

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

那不是函数,那是方法。两者本质上是不同的:

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

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

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

这意味着:函数可以分配给vals/ vars,它们可以作为参数传递给函数、方法和构造函数,它们可以从函数和方法返回。方法不能做任何事情:Scala 是一种面向对象的语言,程序可以操作的所有实体都是对象……而方法不是。

那么,为什么

rdd.groupBy(f)

工作?

好吧,您可以通过 η-expansion 将方法转换为部分应用的函数(这里“部分应用”的意思是“部分应用到this”,而不是参数的子集):

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

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

某些情况下,即使没有明确提供下划线,Scala 也会知道您想要执行 η 展开。这就是为什么

rdd.groupBy(f)

作品。这称为隐式 η 扩展(Scala 语言规范的第 6.26.2 节案例 3),并且由于模棱两可,仅适用于有限数量的案例。

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

IOW:您似乎遇到的根本问题是您混淆了函数和方法,但在这种特殊情况下,它应该确实有效(至少根据我对规范的解释,尽管显然不是根据编译器作者的解释) .

于 2014-07-19T14:18:31.537 回答