Избегайте "задача не сериализуема" с вложенным методом в классе


Я понимаю обычную проблему "задача не сериализуема", которая возникает при доступе к полю или методу, который находится вне области замыкания.

Чтобы исправить это, я обычно определяю локальную копию этих полей / методов, что позволяет избежать необходимости сериализации всего класса:

class MyClass(val myField: Any) { 
  def run() = { 
    val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv") 

    val myField = this.myField 
    println(f.map( _ + myField ).count) 
  } 
} 

Теперь, если я определяю вложенную функцию в методе run, она не может быть сериализована:

class MyClass() { 
  def run() = { 
    val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv") 

    def mapFn(line: String) = line.split(";") 

    val myField = this.myField 
    println(f.map( mapFn( _ ) ).count) 

  } 
} 

Я не понимаю, так как я думал, что "mapFn" будет в области действия... Еще более странно, если я определяю mapFn как val вместо def, тогда это работает:

class MyClass() { 
  def run() = { 
    val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv") 

    val mapFn = (line: String) => line.split(";") 

    println(f.map( mapFn( _ ) ).count)     
  } 
} 

Связано ли это с тем, как Scala представляет вложенные функции?

Каков рекомендуемый способ решения этой проблемы ? Избегать вложенных функций?

1 6

1 ответ:

Разве это не работает таким образом, что в первом случае f.map(mapFN(_)) эквивалентно f.map(new Function() { override def apply(...) = mapFN(...) }), а во втором-просто f.map(mapFN)? Когда вы объявляете метод с def, это, вероятно, просто метод в некотором анонимном классе с неявной $outer ссылкой на заключающий класс. Но map требует Function, поэтому компилятор должен обернуть его. В оболочке вы просто ссылаетесь на некоторый метод этого анонимного класса,но не на сам экземпляр. Если вы используете val, у вас есть прямая ссылка на функция, которую вы передаете в map. Я не уверен насчет этого, просто думаю вслух...