путаница в понимании передачи параметра в scala

Два метода groupBy в Spark RDD объявлены как:

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).


person user2018791    schedule 18.07.2014    source источник
comment
Проблема возникает из-за принципиальной разницы между методами (def) и функциями в Scala. Взгляните на этот ответ, чтобы увидеть, как они взаимодействуют: stackoverflow.com/a/2394063/58808   -  person Ionuț G. Stan    schedule 18.07.2014
comment
попробуй rdd.groupBy(f _, 10)   -  person samthebest    schedule 21.07.2014
comment
этот вопрос содержит полезную информацию по теме. Стоит прочитать: stackoverflow.com/questions/17324247/   -  person maasg    schedule 22.07.2014


Ответы (1)


Я определяю функцию f как:

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

Это не функция, это метод. Они принципиально отличаются:

  • Методы могут быть универсальными, а функции — нет.
  • Методы могут иметь необязательные параметры с аргументами по умолчанию, а функции — нет.
  • Методы могут иметь varargs, а функции — нет.
  • Методы могут иметь неявные аргументы, а функции — нет.

Это 4 ограничения, которые функции имеют по сравнению с методами. Теперь, если они так ограничены, почему мы их используем? Что ж, у функций есть одно важное преимущество:

  • Функции — это объекты, а методы — нет (они принадлежат объектам).

Это означает: функции можно назначать vals/vars, их можно передавать в качестве аргументов функциям, методам и конструкторам, их можно возвращать из функций и методов. Методы ничего из этого сделать не могут: Scala — это объектно-ориентированный язык, все объекты, которыми может манипулировать программа, являются объектами, а методы — нет.

Итак, почему

rdd.groupBy(f)

Работа?

Ну, вы можете преобразовать метод в частично примененную функцию (здесь «частично примененный» означает «частично примененный к this», а не к подмножеству аргументов) через -расширение:

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

Здесь, как это часто бывает в Scala, символ подчеркивания используется в качестве заполнителя (в данном случае для еще не предоставленных аргументов). Мы исправили this метода, оставили аргументы открытыми и создали функцию, соответствующую этому методу.

В некоторых случаях Scala будет знать, что вы хотите выполнить -расширение, даже без явного предоставления символа подчеркивания. Вот почему

rdd.groupBy(f)

работает. Это называется неявное расширение (§6.26.2, случай 3 Спецификации языка Scala) и из-за неоднозначности работает только в ограниченном количестве случаев.

Однако, объяснив все это, я должен признать, что не понимаю, почему ваш второй пример не работает. Согласно моему прочтению спецификации, так и должно быть.

IOW: фундаментальная проблема, с которой вы столкнулись, заключается в том, что вы путаете функции и методы, но в этом конкретном случае это действительно должно работать (по крайней мере, в соответствии с моей интерпретацией спецификации, хотя явно не в соответствии с интерпретацией авторов компилятора).

person Jörg W Mittag    schedule 19.07.2014