【问题标题】:confusion in understanding of passing parameter in scala对scala中传递参数的理解混乱
【发布时间】:2014-09-09 17:26:12
【问题描述】:

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)

【问题讨论】:

标签: scala apache-spark rdd


【解决方案1】:

我将函数 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)

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    相关资源
    最近更新 更多